Merge pull request #73 from vkaelin/vite

Move frontend to vite
This commit is contained in:
Valentin Kaelin 2023-09-21 14:15:13 +02:00 committed by GitHub
commit 57cfccb675
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
94 changed files with 4879 additions and 30050 deletions

View file

@ -4,7 +4,7 @@
<a href="https://discord.gg/RjBzjfk"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="LeagueStats.gg official Discord"></a> <a href="https://discord.gg/RjBzjfk"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="LeagueStats.gg official Discord"></a>
The goal of [leaguestats.gg](https://leaguestats.gg) is to provide global complete data for all League of Legends summoners. The goal of [leaguestats.gg](https://leaguestats.gg) is to provide global complete data for all League of Legends summoners.
Here is an [example](https://leaguestats.gg/summoner/euw/KCRekkles) of stats for some summoner. Here is an [example](https://leaguestats.gg/summoner/euw/KCNEXTADKING) of stats for some summoner.
![Screenshot](https://res.cloudinary.com/kln/image/upload/v1615669773/repository-preview-leaguestats.jpg) ![Screenshot](https://res.cloudinary.com/kln/image/upload/v1615669773/repository-preview-leaguestats.jpg)
@ -14,11 +14,11 @@ Here is an [example](https://leaguestats.gg/summoner/euw/KCRekkles) of stats for
Development environment requirements : Development environment requirements :
- [Node.js](https://nodejs.org/en/download/) >= 12.0.0 - [Node.js](https://nodejs.org/en/download/) >= 18.0.0
- [PostgreSQL](https://www.postgresql.org/download/) - [PostgreSQL](https://www.postgresql.org/download/)
- [Redis](https://redis.io/download) - [Redis](https://redis.io/download)
You can use the `docker-compose.yml` file to quickly setup Postgre and Redis in development. You can use the `docker-compose.yml` file to quickly setup PostgreSQL and Redis in development.
Setting up the docker container: Setting up the docker container:
@ -77,6 +77,7 @@ Deploying the app :
```bash ```bash
> cd client > cd client
> npm run build > npm run build
> npm run preview # to test the build locally
# And # And

View file

@ -1,3 +0,0 @@
> 1%
last 2 versions
not ie <= 8

3
client/.eslintignore Normal file
View file

@ -0,0 +1,3 @@
dist
node_modules
*.html

View file

@ -1,41 +1,13 @@
module.exports = { module.exports = {
root: true, root: true,
env: { env: {
node: true node: true,
},
'extends': [
'plugin:vue/essential',
'plugin:vue/recommended',
'eslint:recommended'
],
rules: {
//'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-console': 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
"vue/html-self-closing": 'off',
'vue/max-attributes-per-line': 'off',
'vue/no-v-html': 'off',
"vue/attributes-order": ["error", {
"order": [
"DEFINITION",
"LIST_RENDERING",
"CONDITIONALS",
"RENDER_MODIFIERS",
"UNIQUE",
"TWO_WAY_BINDING",
"OTHER_DIRECTIVES",
"EVENTS",
"CONTENT",
"GLOBAL",
"OTHER_ATTR"
]
}],
"quotes": [2, "single", { "avoidEscape": true }],
"semi": [2, "never"]
}, },
extends: ['plugin:vue/essential', 'eslint:recommended'],
parserOptions: { parserOptions: {
parser: 'babel-eslint' parser: '@babel/eslint-parser',
} },
rules: {
'vue/multi-word-component-names': 'off',
},
} }

4
client/.gitignore vendored
View file

@ -10,6 +10,7 @@ node_modules
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log*
# Editor directories and files # Editor directories and files
.idea .idea
@ -18,4 +19,5 @@ yarn-error.log*
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw* *.sw?
*.lock

3
client/.prettierignore Normal file
View file

@ -0,0 +1,3 @@
dist
node_modules
src/components/Global/SVGContainer.vue

12
client/.prettierrc.js Normal file
View file

@ -0,0 +1,12 @@
module.exports = {
trailingComma: 'es5',
semi: false,
singleQuote: true,
useTabs: false,
quoteProps: 'consistent',
bracketSpacing: true,
arrowParens: 'always',
printWidth: 100,
endOfLine: 'auto',
plugins: ['prettier-plugin-tailwindcss'],
}

View file

@ -1,29 +1,37 @@
# LeagueStats Frontend # LeagueStats Frontend
## Project setup ## Project setup
``` ```
npm install npm install
``` ```
### Compiles and hot-reloads for development ### Compile and hot-reload for development
``` ```
npm run serve npm run dev
``` ```
### Compiles and minifies for production ### Compile and minify for production
``` ```
npm run build npm run build
``` ```
### Run your tests ### Test the production build locally
``` ```
npm run test npm run preview
``` ```
### Lints and fixes files ### Lint files
``` ```
npm run lint npm run lint
``` ```
### Customize configuration ### Format files
See [Configuration Reference](https://cli.vuejs.org/config/).
```
npm run format
```

View file

@ -1,10 +1,14 @@
module.exports = { module.exports = {
presets: [ presets: ['@babel/preset-env'],
'@vue/app' plugins: [
function () {
return {
visitor: {
MetaProperty(path) {
path.replaceWithSourceString('process')
},
},
}
},
], ],
env: {
production: {
plugins: ['transform-remove-console']
}
}
} }

28
client/index.html Normal file
View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="msapplication-TileColor" content="#38b2ac" />
<meta name="theme-color" content="#ffffff" />
<title>LeagueStats.gg</title>
<meta
name="description"
content="LeagueStats.gg is an Open source website for League of Legends Summoners statistics."
/>
</head>
<body class="relative bg-blue-900 min-w-1200">
<noscript>
<strong
>We're sorry but LeagueStats doesn't work properly without JavaScript enabled. Please enable
it to continue.</strong
>
</noscript>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View file

@ -1,10 +0,0 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"./src/*"
]
}
}
}

31698
client/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,34 +1,40 @@
{ {
"name": "leaguestats-frontend", "name": "leaguestats-frontend",
"version": "0.1.0",
"private": true, "private": true,
"version": "0.1.0",
"scripts": { "scripts": {
"dev": "npm run serve", "dev": "vite",
"serve": "vue-cli-service serve", "build": "vite build",
"build": "vue-cli-service build", "preview": "vite preview --port 8080",
"lint": "vue-cli-service lint" "lint": "eslint --ext .js,.ts,.jsx,.tsx,.vue --ignore-path .eslintignore .",
}, "format": "prettier --write \"**/*.{ts,tsx,js,css,vue}\" --ignore-path .prettierignore"
"dependencies": {
"axios": "^0.21.2",
"portal-vue": "^2.1.7",
"vue": "^2.6.12",
"vue-content-loader": "^0.2.3",
"vue-meta": "^2.4.0",
"vue-plausible": "^1.1.4",
"vue-router": "^3.5.1",
"vue-sticky-sidebar": "^1.0.5",
"vuex": "^3.6.2"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/custom-forms": "^0.2.1", "@babel/eslint-parser": "^7.22.15",
"@vue/cli-plugin-babel": "^4.5.13", "@babel/preset-env": "^7.22.20",
"@vue/cli-plugin-eslint": "^4.5.13", "@tailwindcss/forms": "^0.5.6",
"@vue/cli-service": "^4.5.13", "@vitejs/plugin-vue2": "^2.2.0",
"babel-eslint": "^10.1.0", "autoprefixer": "^10.4.15",
"babel-plugin-transform-remove-console": "^6.9.4", "eslint-config-prettier": "^9.0.0",
"eslint": "^7.27.0", "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-vue": "^7.9.0", "eslint-plugin-vue": "^9.17.0",
"tailwindcss": "^1.9.6", "postcss": "^8.4.30",
"vue-template-compiler": "^2.6.12" "postcss-import": "^12.0.1",
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.4",
"tailwindcss": "^3.3.3",
"vite": "^4.4.5",
"vite-plugin-eslint": "^1.8.1"
},
"dependencies": {
"axios": "^1.5.0",
"plausible-tracker": "^0.3.8",
"portal-vue": "^2.1.7",
"vue": "^2.7.14",
"vue-content-loader": "^0.2.3",
"vue-meta": "^2.4.0",
"vue-router": "^3.6.5",
"vue-sticky-sidebar": "^1.0.5",
"vuex": "^3.6.2"
} }
} }

View file

@ -1,6 +1,6 @@
module.exports = { module.exports = {
plugins: [ plugins: {
require('tailwindcss'), tailwindcss: {},
require('autoprefixer') autoprefixer: {},
] },
} }

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View file

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 707 B

View file

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 416 B

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View file

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View file

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View file

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View file

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="apple-touch-icon" sizes="180x180" href="<%= BASE_URL %>apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="<%= BASE_URL %>favicon-16x16.png">
<link rel="manifest" href="<%= BASE_URL %>site.webmanifest">
<link rel="mask-icon" href="<%= BASE_URL %>safari-pinned-tab.svg" color="#2a4365">
<meta name="msapplication-TileColor" content="#38b2ac">
<meta name="theme-color" content="#ffffff">
<title>LeagueStats.gg</title>
<meta name="description"
content="LeagueStats.gg is an Open source website for League of Legends Summoners statistics.">
</head>
<body class="relative bg-blue-900 min-w-1200">
<noscript>
<strong>We're sorry but LeagueStats doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View file

@ -1,5 +1,5 @@
<template> <template>
<div id="app" class="min-h-screen font-sans antialiased bg-blue-900"> <div id="app" class="min-h-screen bg-blue-900 font-sans antialiased">
<SVGContainer /> <SVGContainer />
<NotificationsContainer /> <NotificationsContainer />
<RunesContainer /> <RunesContainer />

View file

@ -2,12 +2,12 @@
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
height: 8px height: 8px;
} }
::-webkit-scrollbar, ::-webkit-scrollbar,
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: rgba(23, 49, 79, .6); background: rgba(23, 49, 79, 0.6);
} }
.light-scrollbar::-webkit-scrollbar, .light-scrollbar::-webkit-scrollbar,
@ -16,20 +16,20 @@
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: rgba(194, 217, 254, .6); background-color: rgba(194, 217, 254, 0.6);
border-radius: 8px border-radius: 8px;
} }
::selection { ::selection {
@apply text-white bg-blue-1000; @apply bg-blue-1000 text-white;
} }
::-moz-selection { ::-moz-selection {
@apply text-white bg-blue-1000; @apply bg-blue-1000 text-white;
} }
.min-w-1200 { .min-w-1200 {
min-width: 1200px;; min-width: 1200px;
} }
.page-wrapper { .page-wrapper {
@ -52,11 +52,11 @@ button:focus {
} }
.bg-gradient { .bg-gradient {
background: linear-gradient(180deg, #2C5282 0%, rgba(44, 82, 130, 0) 100%); background: linear-gradient(180deg, #2c5282 0%, rgba(44, 82, 130, 0) 100%);
} }
.bg-gradient-x { .bg-gradient-x {
background: linear-gradient(270deg, rgba(44,82,130,1) 0%, rgba(44,82,130,0) 100%); background: linear-gradient(270deg, rgba(44, 82, 130, 1) 0%, rgba(44, 82, 130, 0) 100%);
} }
.text-overflow { .text-overflow {
@ -64,14 +64,25 @@ button:focus {
} }
.heading { .heading {
background: linear-gradient( background: linear-gradient(to top, rgb(34, 92, 155) 0%, rgb(34, 92, 135) 100%);
to top,
rgb(34, 92, 155) 0%,
rgb(34, 92, 135) 100%
);
box-shadow: rgba(235, 248, 255, 0.1) 0px -1px inset; box-shadow: rgba(235, 248, 255, 0.1) 0px -1px inset;
} }
.input-color { .input-color {
background: rgba(23, 49, 79, 0.6); background: rgba(23, 49, 79, 0.6);
} }
/* Checkbox */
.form-checkbox {
@apply h-6 w-6 rounded-md border-blue-800 text-blue-1000;
background: rgba(23, 49, 79, 0.6);
}
.form-checkbox:focus {
@apply border-blue-700 bg-blue-1000 outline-none;
box-shadow: none;
}
.form-checkbox:checked {
@apply border-transparent bg-blue-1000;
}

View file

@ -1,30 +1,17 @@
/* purgecss start ignore */
.Win { .Win {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(1, 97, 28, 0.3) 0%, rgba(44, 82, 130, 0) 45%);
90deg,
rgba(1, 97, 28, 0.3) 0%,
rgba(44, 82, 130, 0) 45%
);
} }
.Fail { .Fail {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(140, 0, 0, 0.3) 0%, rgba(44, 82, 130, 0) 45%);
90deg,
rgba(140, 0, 0, 0.3) 0%,
rgba(44, 82, 130, 0) 45%
);
} }
.Remake { .Remake {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(233, 169, 75, 0.3) 0%, rgba(44, 82, 130, 0) 45%);
90deg,
rgba(233, 169, 75, 0.3) 0%,
rgba(44, 82, 130, 0) 45%
);
} }
.ban::after { .ban::after {
content: ""; content: '';
position: absolute; position: absolute;
left: 0px; left: 0px;
top: 50%; top: 50%;
@ -49,4 +36,3 @@
left: -7px; left: -7px;
top: -5px; top: -5px;
} }
/* purgecss end ignore */

View file

@ -1,16 +1,18 @@
/* purgecss start ignore */
/* Fade transitions */ /* Fade transitions */
.fade-enter-active, .fade-leave-active { .fade-enter-active,
.fade-leave-active {
transition: opacity 2s; transition: opacity 2s;
} }
.fade-fast-enter-active, .fade-fast-leave-active { .fade-fast-enter-active,
transition: opacity .3s; .fade-fast-leave-active {
transition: opacity 0.3s;
} }
.fade-fast-enter, .fade-fast-leave-to, .fade-fast-enter,
.fade-enter, .fade-leave-to { .fade-fast-leave-to,
.fade-enter,
.fade-leave-to {
opacity: 0; opacity: 0;
} }
@ -31,21 +33,23 @@
@apply transition duration-500 ease-in-out; @apply transition duration-500 ease-in-out;
} }
.tab-enter, .tab-enter-leave-to { .tab-enter,
.tab-enter-leave-to {
@apply opacity-0; @apply opacity-0;
} }
.tab-enter-to, .tab-enter-leave { .tab-enter-to,
.tab-enter-leave {
@apply opacity-100; @apply opacity-100;
} }
/* Scale-fade transition */ /* Scale-fade transition */
.scale-fade-enter-active { .scale-fade-enter-active {
@apply transition-all duration-75 ease-out transform; @apply transform transition-all duration-75 ease-out;
} }
.scale-fade-leave-active { .scale-fade-leave-active {
@apply transition-all duration-75 ease-in transform; @apply transform transition-all duration-75 ease-in;
} }
.scale-fade-enter, .scale-fade-enter,
@ -84,5 +88,3 @@
transform: scale(4); transform: scale(4);
opacity: 0; opacity: 0;
} }
/* purgecss end ignore */

View file

@ -2,12 +2,12 @@
<div <div
:style="{ width: size, height: size, margin }" :style="{ width: size, height: size, margin }"
class="relative" class="relative"
style="transform: rotateZ(45deg);" style="transform: rotateZ(45deg)"
> >
<div class="relative float-left w-1/2 cube-1 cube h-1/2"></div> <div class="cube-1 cube relative float-left h-1/2 w-1/2"></div>
<div class="relative float-left w-1/2 cube-2 cube h-1/2"></div> <div class="cube-2 cube relative float-left h-1/2 w-1/2"></div>
<div class="relative float-left w-1/2 cube-4 cube h-1/2"></div> <div class="cube-4 cube relative float-left h-1/2 w-1/2"></div>
<div class="relative float-left w-1/2 cube-3 cube h-1/2"></div> <div class="cube-3 cube relative float-left h-1/2 w-1/2"></div>
</div> </div>
</template> </template>
@ -16,17 +16,17 @@ export default {
props: { props: {
color: { color: {
type: String, type: String,
default: '#bee3f8' default: '#bee3f8',
}, },
size: { size: {
type: String, type: String,
default: '30px' default: '30px',
}, },
margin: { margin: {
type: String, type: String,
default: '0 auto' default: '0 auto',
} },
} },
} }
</script> </script>
@ -36,8 +36,8 @@ export default {
} }
.cube:before { .cube:before {
content: ""; content: '';
@apply absolute top-0 left-0 w-full h-full bg-blue-300; @apply absolute left-0 top-0 h-full w-full bg-blue-300;
animation: cubeAngle 2.4s infinite linear both; animation: cubeAngle 2.4s infinite linear both;
transform-origin: 100% 100%; transform-origin: 100% 100%;
} }

View file

@ -1,8 +1,8 @@
<template> <template>
<div :style="{width: width}" class="text-center spinner"> <div :style="{ width: width }" class="spinner text-center">
<div :style="dotStyle" class="inline-block rounded-full bounce1"></div> <div :style="dotStyle" class="bounce1 inline-block rounded-full"></div>
<div :style="dotStyle" class="inline-block rounded-full bounce2"></div> <div :style="dotStyle" class="bounce2 inline-block rounded-full"></div>
<div :style="dotStyle" class="inline-block rounded-full bounce3"></div> <div :style="dotStyle" class="bounce3 inline-block rounded-full"></div>
</div> </div>
</template> </template>
@ -11,16 +11,16 @@ export default {
props: { props: {
color: { color: {
type: String, type: String,
default: '#90cdf4' default: '#90cdf4',
}, },
dotWidth: { dotWidth: {
type: String, type: String,
default: '18px' default: '18px',
}, },
width: { width: {
type: String, type: String,
default: '70px' default: '70px',
} },
}, },
computed: { computed: {
@ -28,10 +28,10 @@ export default {
return { return {
backgroundColor: this.color, backgroundColor: this.color,
height: this.dotWidth, height: this.dotWidth,
width: this.dotWidth width: this.dotWidth,
} }
} },
} },
} }
</script> </script>

View file

@ -14,34 +14,34 @@ export default {
props: { props: {
imageSource: { imageSource: {
type: String, type: String,
required: true required: true,
}, },
imageClass: { imageClass: {
type: String, type: String,
required: false, required: false,
default: '' default: '',
}, },
backgroundSize: { backgroundSize: {
type: String, type: String,
required: false, required: false,
default: 'cover' default: 'cover',
}, },
moreBackgrounds: { moreBackgrounds: {
type: String, type: String,
required: false, required: false,
default: '' default: '',
}, },
transitionName: { transitionName: {
type: String, type: String,
required: false, required: false,
default: '' default: '',
} },
}, },
data() { data() {
return { return {
imageState: 'loading', imageState: 'loading',
asyncImage: new Image() asyncImage: new Image(),
} }
}, },
@ -51,7 +51,7 @@ export default {
return `background-image: ${this.moreBackgrounds} url(${this.asyncImage.src}); background-size: ${this.backgroundSize}` return `background-image: ${this.moreBackgrounds} url(${this.asyncImage.src}); background-size: ${this.backgroundSize}`
} }
return '' return ''
} },
}, },
mounted() { mounted() {
@ -68,7 +68,7 @@ export default {
}, },
imageOnLoad() { imageOnLoad() {
this.imageState = 'loaded' this.imageState = 'loaded'
} },
} },
} }
</script> </script>

View file

@ -1,20 +1,20 @@
<template> <template>
<div ref="container" @mousedown="addRipple" class="relative overflow-hidden cursor-pointer"> <div ref="container" @mousedown="addRipple" class="relative cursor-pointer overflow-hidden">
<transition-group <transition-group
class="absolute top-0 left-0 w-full h-full pointer-events-none" class="pointer-events-none absolute left-0 top-0 h-full w-full"
name="grow" name="grow"
tag="div" tag="div"
> >
<div <div
v-for="ripple in ripples" v-for="ripple in ripples"
:key="ripple.id" :key="ripple.id"
class="absolute w-full h-full rounded-full opacity-0 pointer-events-none" class="pointer-events-none absolute h-full w-full rounded-full opacity-0"
:style="{ :style="{
top: ripple.top, top: ripple.top,
left: ripple.left, left: ripple.left,
width: ripple.width, width: ripple.width,
height: ripple.height, height: ripple.height,
background: color background: color,
}" }"
></div> ></div>
</transition-group> </transition-group>
@ -27,8 +27,8 @@ export default {
props: { props: {
color: { color: {
type: String, type: String,
default: 'rgba(255, 255, 255, 0.3)' default: 'rgba(255, 255, 255, 0.3)',
} },
}, },
data() { data() {
@ -61,17 +61,17 @@ export default {
height: `${this.rippleWidth}px`, height: `${this.rippleWidth}px`,
left: `${e.clientX - left - this.halfRippleWidth}px`, left: `${e.clientX - left - this.halfRippleWidth}px`,
top: `${e.clientY - top - this.halfRippleWidth}px`, top: `${e.clientY - top - this.halfRippleWidth}px`,
id: rippleId id: rippleId,
}) })
// Remove ripple // Remove ripple
setTimeout(() => { setTimeout(() => {
this.ripples = this.ripples.filter(r => r.id !== rippleId) this.ripples = this.ripples.filter((r) => r.id !== rippleId)
}, 400) }, 400)
}, },
purgeRipples() { purgeRipples() {
this.ripples = [] this.ripples = []
} },
} },
} }
</script> </script>

View file

@ -17,7 +17,7 @@
<div <div
v-show="isOpen" v-show="isOpen"
ref="content" ref="content"
class="bg-blue-1000 fixed z-50 py-2 rounded-md shadow" class="fixed z-50 rounded-md bg-blue-1000 py-2 shadow"
:style="{ ...position }" :style="{ ...position }"
> >
<slot></slot> <slot></slot>
@ -25,7 +25,7 @@
</portal> </portal>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
@ -37,19 +37,21 @@ export default {
directionBottom: true, directionBottom: true,
directionRight: true, directionRight: true,
directionChecked: false, directionChecked: false,
width: 0 width: 0,
} }
}, },
computed: { computed: {
position() { position() {
const valuetoRemove = this.directionBottom ? 0 : this.height() const valuetoRemove = this.directionBottom ? 0 : this.height()
const leftValue = this.directionRight ? this.left + this.offset : this.left - this.width - this.offset / 2 const leftValue = this.directionRight
? this.left + this.offset
: this.left - this.width - this.offset / 2
return { return {
left: `${leftValue}px`, left: `${leftValue}px`,
top: `${this.top + this.offset - valuetoRemove}px`, top: `${this.top + this.offset - valuetoRemove}px`,
} }
} },
}, },
created() { created() {
@ -67,8 +69,8 @@ export default {
this.width = contentRect.width this.width = contentRect.width
const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight) const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight)
const viewWidth = Math.max(document.documentElement.clientWidth, window.innerWidth) const viewWidth = Math.max(document.documentElement.clientWidth, window.innerWidth)
this.directionBottom = (contentRect.bottom + this.offset) < viewHeight this.directionBottom = contentRect.bottom + this.offset < viewHeight
this.directionRight = (this.left + this.width + triggerRect.width + this.offset) < viewWidth this.directionRight = this.left + this.width + triggerRect.width + this.offset < viewWidth
}, },
handleScroll() { handleScroll() {
this.isOpen = false this.isOpen = false
@ -100,7 +102,7 @@ export default {
this.left = event.clientX this.left = event.clientX
this.top = event.clientY this.top = event.clientY
this.isOpen = true this.isOpen = true
} },
} },
} }
</script> </script>

View file

@ -1,24 +1,24 @@
<template> <template>
<button <button
@click="btnClicked" @click="btnClicked"
:class="[btnClass, {'loading': loading}, {'pr-12': loading}]" :class="[btnClass, { loading: loading }, { 'pr-12': loading }]"
:disabled="loading" :disabled="loading"
class="relative select-none" class="relative select-none"
type="button" type="button"
> >
<slot>Send</slot> <slot>Send</slot>
<span class="spinner absolute opacity-0 left-auto"> <span class="spinner absolute left-auto opacity-0">
<span <span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full" class="absolute right-0 inline-block h-4 w-4 rounded-full border-[3px] border-white opacity-100"
></span> ></span>
<span <span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full" class="absolute right-0 inline-block h-4 w-4 rounded-full border-[3px] border-white opacity-100"
></span> ></span>
<span <span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full" class="absolute right-0 inline-block h-4 w-4 rounded-full border-[3px] border-white opacity-100"
></span> ></span>
<span <span
class="inline-block absolute right-0 w-4 h-4 opacity-100 border-3 border-white rounded-full" class="absolute right-0 inline-block h-4 w-4 rounded-full border-[3px] border-white opacity-100"
></span> ></span>
</span> </span>
</button> </button>
@ -30,20 +30,20 @@ export default {
btnClass: { btnClass: {
type: String, type: String,
required: false, required: false,
default: '' default: '',
}, },
loading: { loading: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
} },
}, },
methods: { methods: {
btnClicked() { btnClicked() {
this.$emit('clicked') this.$emit('clicked')
} },
} },
} }
</script> </script>

View file

@ -1,13 +1,13 @@
<template> <template>
<form <form
@submit.prevent="formSubmit" @submit.prevent="formSubmit"
:class="{'max-w-lg': !homepage}" :class="{ 'max-w-lg': !homepage }"
class="flex self-start w-full h-full text-lg text-teal-100" class="flex h-full w-full self-start text-lg text-teal-100"
> >
<div <div
v-if="open" v-if="open"
@click="open = false" @click="open = false"
:style="{opacity: homepage ? 0 : 0.9}" :style="{ opacity: homepage ? 0 : 0.9 }"
class="fixed inset-0 z-20 bg-gray-900" class="fixed inset-0 z-20 bg-gray-900"
></div> ></div>
<div class="relative w-full"> <div class="relative w-full">
@ -17,7 +17,7 @@
v-model="summoner" v-model="summoner"
@focus="open = true" @focus="open = true"
:class="dropdown ? 'bg-blue-1000' : 'input-color'" :class="dropdown ? 'bg-blue-1000' : 'input-color'"
class="relative z-30 w-full py-4 pl-6 pr-32 font-bold placeholder-teal-100 placeholder-opacity-75 rounded-lg outline-none focus:bg-blue-1000 summoner-input bypass-click" class="summoner-input bypass-click relative z-30 w-full rounded-lg py-4 pl-6 pr-32 font-bold placeholder-teal-100 placeholder-opacity-75 outline-none focus:bg-blue-1000"
spellcheck="false" spellcheck="false"
type="text" type="text"
placeholder="Search summoner" placeholder="Search summoner"
@ -25,21 +25,21 @@
<button <button
v-if="homepage" v-if="homepage"
ref="submit" ref="submit"
class="absolute right-0 z-40 w-12 h-full hover:text-teal-200" class="absolute right-0 z-40 h-full w-12 hover:text-teal-200"
type="submit" type="submit"
> >
<svg class="absolute w-4 h-4 vertical-center horizontal-center"> <svg class="vertical-center horizontal-center absolute h-4 w-4">
<use xlink:href="#search" /> <use xlink:href="#search" />
</svg> </svg>
</button> </button>
<button <button
v-if="!homepage" v-if="!homepage"
@click="open = true" @click="open = true"
class="w-full h-10 px-4 -mt-px text-base font-light text-left text-blue-200 rounded-md bg-blue-1000" class="-mt-px h-10 w-full rounded-md bg-blue-1000 px-4 text-left text-base font-light text-blue-200"
type="button" type="button"
> >
<div class="flex items-center space-x-3"> <div class="flex items-center space-x-3">
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#search" /> <use xlink:href="#search" />
</svg> </svg>
<span>Search summoner (Press "/" to focus)</span> <span>Search summoner (Press "/" to focus)</span>
@ -76,14 +76,14 @@ import SearchFormRegion from '@/components/Form/SearchFormRegion.vue'
export default { export default {
components: { components: {
SearchFormDropdown, SearchFormDropdown,
SearchFormRegion SearchFormRegion,
}, },
props: { props: {
homepage: { homepage: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
data() { data() {
@ -96,7 +96,7 @@ export default {
computed: { computed: {
...mapState({ ...mapState({
selectedRegion: state => state.settings.region selectedRegion: (state) => state.settings.region,
}), }),
}, },
@ -113,7 +113,7 @@ export default {
this.summoner = newRoute.params.name this.summoner = newRoute.params.name
this.dropdown = false this.dropdown = false
this.open = false this.open = false
} },
}, },
created() { created() {
@ -162,7 +162,7 @@ export default {
const inner = document.createElement('div') const inner = document.createElement('div')
outer.appendChild(inner) outer.appendChild(inner)
const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth) const scrollbarWidth = outer.offsetWidth - inner.offsetWidth
outer.parentNode.removeChild(outer) outer.parentNode.removeChild(outer)
@ -181,7 +181,7 @@ export default {
windowBlur() { windowBlur() {
this.open = false this.open = false
}, },
} },
} }
</script> </script>

View file

@ -1,13 +1,13 @@
<template> <template>
<div <div
:class="homepage ? 'mt-2' : 'mt-1'" :class="homepage ? 'mt-2' : 'mt-1'"
class="absolute z-30 w-full bg-blue-800 rounded-lg shadow-md" class="absolute z-30 w-full rounded-lg bg-blue-800 shadow-md"
> >
<div class="shadow"> <div class="shadow">
<div class="pt-3"> <div class="pt-3">
<div v-if="!homepage" class="relative px-3 bypass-click"> <div v-if="!homepage" class="bypass-click relative px-3">
<button class="absolute w-12 h-full text-blue-200 hover:text-white" type="submit"> <button class="absolute h-full w-12 text-blue-200 hover:text-white" type="submit">
<svg class="absolute w-4 h-4 vertical-center horizontal-center"> <svg class="vertical-center horizontal-center absolute h-4 w-4">
<use xlink:href="#search" /> <use xlink:href="#search" />
</svg> </svg>
</button> </button>
@ -15,7 +15,7 @@
ref="input" ref="input"
@input="$emit('input', $event.target.value)" @input="$emit('input', $event.target.value)"
:value="value" :value="value"
class="w-full py-2 pl-12 pr-32 placeholder-blue-200 placeholder-opacity-75 bg-blue-700 border border-blue-500 rounded-md outline-none focus:bg-blue-760 summoner-input" class="summoner-input w-full rounded-md border border-blue-500 bg-blue-700 py-2 pl-12 pr-32 placeholder-blue-200 placeholder-opacity-75 outline-none focus:bg-blue-760"
type="text" type="text"
placeholder="Search summoner" placeholder="Search summoner"
spellcheck="false" spellcheck="false"
@ -23,10 +23,10 @@
<button <button
v-if="!homepage && value.length" v-if="!homepage && value.length"
@click="$emit('input', '')" @click="$emit('input', '')"
class="absolute right-0 flex items-center justify-center p-1 mr-24 text-blue-200 rounded-full vertical-center hover:text-white" class="vertical-center absolute right-0 mr-24 flex items-center justify-center rounded-full p-1 text-blue-200 hover:text-white"
type="button" type="button"
> >
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#times" /> <use xlink:href="#times" />
</svg> </svg>
</button> </button>
@ -35,13 +35,13 @@
</div> </div>
</div> </div>
<div <div
:style="{maxHeight: homepage ? '300px' : '480px'}" :style="{ maxHeight: homepage ? '300px' : '480px' }"
class="px-3 pb-6 overflow-y-auto light-scrollbar" class="light-scrollbar overflow-y-auto px-3 pb-6"
> >
<div :class="{'mt-4': !homepage}"> <div :class="{ 'mt-4': !homepage }">
<div v-if="recentSearches.length" class="text-base text-blue-100">Recent</div> <div v-if="recentSearches.length" class="text-base text-blue-100">Recent</div>
<div v-else-if="favorites.length === 0" class="flex items-center space-x-2"> <div v-else-if="favorites.length === 0" class="flex items-center space-x-2">
<svg class="w-4 h-4 text-blue-100"> <svg class="h-4 w-4 text-blue-100">
<use xlink:href="#info" /> <use xlink:href="#info" />
</svg> </svg>
<div class="text-base text-blue-100">Summoner example</div> <div class="text-base text-blue-100">Summoner example</div>
@ -69,14 +69,14 @@
<SearchFormDropdownPlayer <SearchFormDropdownPlayer
@close="close" @close="close"
@mousemove.native="onHover(1)" @mousemove.native="onHover(1)"
:player="{name: 'KC Rekkles', icon: 7, region: 'euw'}" :player="{ name: 'KC NEXT ADKING', icon: 29, region: 'euw' }"
:selected="selected === 1" :selected="selected === 1"
:favorites-list="false" :favorites-list="false"
/> />
</template> </template>
</div> </div>
</div> </div>
<div v-if="favorites.length" :class="{'mt-4': recentSearches.length}"> <div v-if="favorites.length" :class="{ 'mt-4': recentSearches.length }">
<div class="text-base text-blue-100">Favorites</div> <div class="text-base text-blue-100">Favorites</div>
<div <div
ref="favorites" ref="favorites"
@ -99,22 +99,24 @@
</div> </div>
</div> </div>
</div> </div>
<div class="px-4 py-4 bg-blue-1000 rounded-b-md"> <div class="rounded-b-md bg-blue-1000 px-4 py-4">
<div class="flex items-center justify-between select-none text-xxs"> <div class="flex select-none items-center justify-between text-xxs">
<div class="space-x-2"> <div class="space-x-2">
<span class="text-xs font-medium text-blue-700 bg-blue-100 rounded-md key">Enter</span> <span class="key rounded-md bg-blue-100 text-xs font-medium text-blue-700">Enter</span>
<span>to select</span> <span>to select</span>
</div> </div>
<div class="space-x-2"> <div class="space-x-2">
<span class="text-xs font-medium text-blue-700 bg-blue-100 rounded-md key">&darr; &uarr;</span> <span class="key rounded-md bg-blue-100 text-xs font-medium text-blue-700"
>&darr; &uarr;</span
>
<span>to navigate</span> <span>to navigate</span>
</div> </div>
<div class="space-x-2"> <div class="space-x-2">
<span class="text-xs font-medium text-blue-700 bg-blue-100 rounded-md key">Escape</span> <span class="key rounded-md bg-blue-100 text-xs font-medium text-blue-700">Escape</span>
<span>to close</span> <span>to close</span>
</div> </div>
<div class="space-x-2"> <div class="space-x-2">
<span class="text-xs font-medium text-blue-700 bg-blue-100 rounded-md key">CTRL K</span> <span class="key rounded-md bg-blue-100 text-xs font-medium text-blue-700">CTRL K</span>
<span>to open</span> <span>to open</span>
</div> </div>
</div> </div>
@ -137,16 +139,16 @@ export default {
props: { props: {
dropdown: { dropdown: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
homepage: { homepage: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
value: { value: {
type: String, type: String,
required: true required: true,
} },
}, },
data() { data() {
@ -166,7 +168,7 @@ export default {
recentSearchesSliced() { recentSearchesSliced() {
return this.recentSearches.slice(0, 4) return this.recentSearches.slice(0, 4)
}, },
...mapState('settings', ['favorites', 'recentSearches']) ...mapState('settings', ['favorites', 'recentSearches']),
}, },
created() { created() {
@ -206,9 +208,12 @@ export default {
} }
// Click outside to close region dropdown // Click outside to close region dropdown
if (this.$refs['region-dropdown'] && if (
this.$refs['region-dropdown'] &&
e.target !== this.$refs['region-dropdown'] && e.target !== this.$refs['region-dropdown'] &&
!this.$refs['region-dropdown'].contains(e.target) && this.dropdown) { !this.$refs['region-dropdown'].contains(e.target) &&
this.dropdown
) {
this.toggle() this.toggle()
} }
@ -226,17 +231,18 @@ export default {
} }
} }
if (this.bypassKeys.includes(e.key) || if (this.bypassKeys.includes(e.key) || (e.key === 'k' && (e.ctrlKey || e.metaKey))) {
(e.key === 'k' && (e.ctrlKey || e.metaKey))) {
return return
} }
const input = document.querySelector('.summoner-input') const input = document.querySelector('.summoner-input')
input.focus() input.focus()
}, },
onArrow() { onArrow() {
const scrollIntoBlock = this.selected === 1 ? 'end' : (this.selected >= 7 ? 'start' : 'nearest') const scrollIntoBlock = this.selected === 1 ? 'end' : this.selected >= 7 ? 'start' : 'nearest'
if (this.selected > this.recentSearchesCount) { if (this.selected > this.recentSearchesCount) {
this.$refs.favorites.children[this.selected - this.recentSearchesCount - 1].scrollIntoView({ block: scrollIntoBlock }) this.$refs.favorites.children[this.selected - this.recentSearchesCount - 1].scrollIntoView({
block: scrollIntoBlock,
})
} else { } else {
this.$refs.searches.children[this.selected - 1].scrollIntoView({ block: scrollIntoBlock }) this.$refs.searches.children[this.selected - 1].scrollIntoView({ block: scrollIntoBlock })
} }
@ -263,20 +269,22 @@ export default {
return return
} }
const player = this.allPlayers[this.selected - 1] const player = this.allPlayers[this.selected - 1]
this.$router.push(`/summoner/${player.region}/${player.name}`).catch(() => { }) this.$router.push(`/summoner/${player.region}/${player.name}`).catch(() => {})
this.close() this.close()
}, },
toggle() { toggle() {
this.$emit('toggle') this.$emit('toggle')
}, },
} },
} }
</script> </script>
<style scoped> <style scoped>
.key { .key {
padding: 0.2rem 0.45rem; padding: 0.2rem 0.45rem;
box-shadow: 0 2px 0 0 #3182ce, 0 5px 3px 0 rgba(0, 0, 0, 0.1), box-shadow:
0 2px 0 0 #3182ce,
0 5px 3px 0 rgba(0, 0, 0, 0.1),
0 5px 2px 0 rgba(0, 0, 0, 0.06); 0 5px 2px 0 rgba(0, 0, 0, 0.06);
} }
</style> </style>

View file

@ -1,27 +1,31 @@
<template> <template>
<router-link <router-link
@click.native="close" @click.native="close"
:to="{ name: 'summoner', params: { region: player.region, name: player.name }}" :to="{ name: 'summoner', params: { region: player.region, name: player.name } }"
:title="player.name" :title="player.name"
:class="selected ? 'bg-blue-760' : 'bg-blue-900'" :class="selected ? 'bg-blue-760' : 'bg-blue-900'"
class="flex items-center justify-between w-full px-4 py-3 mt-1 text-blue-200 rounded-md shadow-md cursor-pointer select-none bypass-click" class="bypass-click mt-1 flex w-full cursor-pointer select-none items-center justify-between rounded-md px-4 py-3 text-blue-200 shadow-md"
role="option" role="option"
> >
<div class="flex items-center"> <div class="flex items-center">
<svg v-if="favoritesList" class="w-5 h-5 text-yellow-400"> <svg v-if="favoritesList" class="h-5 w-5 text-yellow-400">
<use xlink:href="#star-outline" /> <use xlink:href="#star-outline" />
</svg> </svg>
<svg v-else class="w-5 h-5"> <svg v-else class="h-5 w-5">
<use xlink:href="#time" /> <use xlink:href="#time" />
</svg> </svg>
<div class="w-20"> <div class="w-20">
<div <div
class="inline-flex px-2 py-1 ml-6 text-xs font-semibold text-white uppercase bg-blue-800 rounded" class="ml-6 inline-flex rounded bg-blue-800 px-2 py-1 text-xs font-semibold uppercase text-white"
>{{ player.region }}</div> >
{{ player.region }}
</div>
</div> </div>
<div <div
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/profile-icons/${player.icon}.jpg')`}" :style="{
class="w-6 h-6 ml-2 bg-center bg-cover rounded-full" backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/profile-icons/${player.icon}.jpg')`,
}"
class="ml-2 h-6 w-6 rounded-full bg-cover bg-center"
></div> ></div>
<div class="ml-2 text-base">{{ player.name }}</div> <div class="ml-2 text-base">{{ player.name }}</div>
</div> </div>
@ -29,17 +33,17 @@
<button <button
v-if="!favoritesList" v-if="!favoritesList"
@click.prevent="favoriteClick" @click.prevent="favoriteClick"
class="flex items-center justify-center p-2 rounded-full hover:text-yellow-400 hover:bg-blue-700" class="flex items-center justify-center rounded-full p-2 hover:bg-blue-700 hover:text-yellow-400"
> >
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#star" /> <use xlink:href="#star" />
</svg> </svg>
</button> </button>
<button <button
@click.prevent="closeClick" @click.prevent="closeClick"
class="p-2 rounded-full cursor-pointerhover:text-white hover:bg-blue-700" class="cursor-pointerhover:text-white rounded-full p-2 hover:bg-blue-700"
> >
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#times" /> <use xlink:href="#times" />
</svg> </svg>
</button> </button>
@ -62,8 +66,8 @@ export default {
}, },
selected: { selected: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
methods: { methods: {
@ -80,7 +84,7 @@ export default {
favoriteClick() { favoriteClick() {
this.updateFavorite(this.player) this.updateFavorite(this.player)
}, },
...mapActions('settings', ['removeRecentSearch', 'updateFavorite']) ...mapActions('settings', ['removeRecentSearch', 'updateFavorite']),
}, },
} }
</script> </script>

View file

@ -2,15 +2,15 @@
<div> <div>
<div <div
:class="[homepage ? 'mr-12' : 'mr-4']" :class="[homepage ? 'mr-12' : 'mr-4']"
class="absolute right-0 z-30 flex items-center h-full vertical-center" class="vertical-center absolute right-0 z-30 flex h-full items-center"
> >
<div <div
@click="toggle" @click="toggle"
:class="[selectRegionClasses]" :class="[selectRegionClasses]"
class="flex items-center transition duration-150 ease-in-out border-2 border-transparent rounded cursor-pointer hover:text-white" class="flex cursor-pointer items-center rounded border-2 border-transparent transition duration-150 ease-in-out hover:text-white"
> >
<span class="font-bold uppercase select-none selected">{{ selectedRegion }}</span> <span class="selected select-none font-bold uppercase">{{ selectedRegion }}</span>
<svg class="w-4 h-4 ml-1 -mr-1"> <svg class="-mr-1 ml-1 h-4 w-4">
<use xlink:href="#caret-down" /> <use xlink:href="#caret-down" />
</svg> </svg>
</div> </div>
@ -19,18 +19,18 @@
<div <div
v-show="dropdown" v-show="dropdown"
:class="[dropdownClasses]" :class="[dropdownClasses]"
class="absolute right-0 z-30 text-white shadow cursor-pointer" class="absolute right-0 z-30 cursor-pointer text-white shadow"
> >
<div <div
v-for="(region, index) in regions" v-for="(region, index) in regions"
:key="region" :key="region"
@click="selectRegion(region)" @click="selectRegion(region)"
:class="classRegions(index)" :class="classRegions(index)"
class="relative py-1 pl-5 pr-2 text-xs text-right select-none bg-blue-1000 hover:bg-blue-800" class="relative select-none bg-blue-1000 py-1 pl-5 pr-2 text-right text-xs hover:bg-blue-800"
> >
<svg <svg
v-if="region.toLowerCase() === selectedRegion" v-if="region.toLowerCase() === selectedRegion"
class="absolute w-3 h-3 fill-current vertical-center offsetIcon" class="vertical-center offsetIcon absolute h-3 w-3 fill-current"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" viewBox="0 0 512 512"
> >
@ -52,12 +52,12 @@ export default {
props: { props: {
dropdown: { dropdown: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
homepage: { homepage: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
data() { data() {
@ -87,7 +87,7 @@ export default {
dropdownClasses() { dropdownClasses() {
return { return {
'offsetDropDown mr-4 rounded': !this.homepage, 'offsetDropDown mr-4 rounded': !this.homepage,
'offsetDropDownXl rounded-b': this.homepage 'offsetDropDownXl rounded-b': this.homepage,
} }
}, },
selectRegionClasses() { selectRegionClasses() {
@ -99,7 +99,7 @@ export default {
} }
}, },
...mapState({ ...mapState({
selectedRegion: state => state.settings.region selectedRegion: (state) => state.settings.region,
}), }),
}, },
@ -107,7 +107,7 @@ export default {
classRegions(index) { classRegions(index) {
return { return {
'rounded-t': index === 0, 'rounded-t': index === 0,
'rounded-b': index === this.regions.length - 1 'rounded-b': index === this.regions.length - 1,
} }
}, },
selectRegion(region) { selectRegion(region) {
@ -118,7 +118,7 @@ export default {
this.$emit('toggle') this.$emit('toggle')
}, },
...mapActions('settings', ['updateSettings']), ...mapActions('settings', ['updateSettings']),
} },
} }
</script> </script>

View file

@ -1,32 +1,34 @@
<template> <template>
<div class="relative z-10 text-sm leading-tight text-teal-400 select-none switch"> <div class="switch relative z-10 select-none text-sm leading-tight text-teal-400">
<input <input
v-model="selected" v-model="selected"
id="toggle-on" id="toggle-on"
class="hidden toggle toggle-left" class="toggle toggle-left hidden"
:value="true" :value="true"
type="radio" type="radio"
/> />
<label <label
:class="{'selected-label': selected}" :class="{ 'selected-label': selected }"
for="toggle-on" for="toggle-on"
class="inline-block py-1 border-t-2 border-b-2 border-l-2 border-r border-teal-500 rounded-l-full cursor-pointer" class="inline-block cursor-pointer rounded-l-full border-b-2 border-l-2 border-r border-t-2 border-teal-500 py-1"
>{{ leftLabel }}</label> >{{ leftLabel }}</label
>
<input <input
v-model="selected" v-model="selected"
id="toggle-off" id="toggle-off"
class="hidden toggle toggle-right" class="toggle toggle-right hidden"
:value="false" :value="false"
type="radio" type="radio"
/> />
<label <label
:class="{'selected-label': !selected}" :class="{ 'selected-label': !selected }"
for="toggle-off" for="toggle-off"
class="inline-block py-1 border-t-2 border-b-2 border-l border-r-2 border-teal-500 rounded-r-full cursor-pointer" class="inline-block cursor-pointer rounded-r-full border-b-2 border-l border-r-2 border-t-2 border-teal-500 py-1"
>{{ rightLabel }}</label> >{{ rightLabel }}</label
>
<div <div
:class="selected ? 'left-checked' : 'right-checked'" :class="selected ? 'left-checked' : 'right-checked'"
class="absolute inset-0 w-1/2 bg-teal-500 selector" class="selector absolute inset-0 w-1/2 bg-teal-500"
></div> ></div>
</div> </div>
</template> </template>
@ -45,7 +47,7 @@ export default {
value: { value: {
type: Boolean, type: Boolean,
required: true, required: true,
} },
}, },
computed: { computed: {
selected: { selected: {
@ -54,7 +56,7 @@ export default {
}, },
set(value) { set(value) {
this.$emit('updateValue', value) this.$emit('updateValue', value)
} },
}, },
}, },
} }
@ -73,7 +75,8 @@ export default {
.selector { .selector {
z-index: -1; z-index: -1;
transition: left 200ms cubic-bezier(0.77, 0, 0.175, 1), transition:
left 200ms cubic-bezier(0.77, 0, 0.175, 1),
border-radius 200ms cubic-bezier(0.77, 0, 0.175, 1); border-radius 200ms cubic-bezier(0.77, 0, 0.175, 1);
} }

View file

@ -14,11 +14,11 @@ import { mapState } from 'vuex'
export default { export default {
components: { components: {
PopupNotification PopupNotification,
}, },
computed: { computed: {
...mapState('notification', ['notifications']) ...mapState('notification', ['notifications']),
} },
} }
</script> </script>

View file

@ -3,16 +3,16 @@
<div <div
:class="{ :class="{
'bg-red-500': notification.type === 'error', 'bg-red-500': notification.type === 'error',
'bg-green-500': notification.type === 'success' 'bg-green-500': notification.type === 'success',
}" }"
class="relative p-6 pr-10 mt-2 text-white rounded-lg shadow-md" class="relative mt-2 rounded-lg p-6 pr-10 text-white shadow-md"
style="min-width: 240px" style="min-width: 240px"
> >
<button <button
@click="deleteNotification" @click="deleteNotification"
class="absolute top-0 right-0 block px-1 py-1 mx-1 my-1 border border-transparent rounded-full cursor-pointer focus:outline-none hover:border-white" class="absolute right-0 top-0 mx-1 my-1 block cursor-pointer rounded-full border border-transparent px-1 py-1 hover:border-white focus:outline-none"
> >
<svg class="w-3 h-3 fill-current" viewBox="0 0 20 20"> <svg class="h-3 w-3 fill-current" viewBox="0 0 20 20">
<path <path
d="M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z" d="M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z"
/> />
@ -42,13 +42,13 @@ export default {
props: { props: {
notification: { notification: {
type: Object, type: Object,
required: true required: true,
} },
}, },
data() { data() {
return { return {
timeout: null timeout: null,
} }
}, },
@ -63,7 +63,7 @@ export default {
deleteNotification() { deleteNotification() {
this.remove(this.notification) this.remove(this.notification)
}, },
...mapActions('notification', ['remove']) ...mapActions('notification', ['remove']),
} },
} }
</script> </script>

View file

@ -1,11 +1,13 @@
<template> <template>
<footer class="pt-20 pb-4 text-blue-200"> <footer class="pb-4 pt-20 text-blue-200">
<p <p
class="absolute leading-tight text-center pointer-events-none horizontal-center text-xxs" class="horizontal-center pointer-events-none absolute text-center text-xxs leading-tight"
style="color: #5d80af;" style="color: #5d80af"
> >
LeagueStats.gg isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. LeagueStats.gg isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot
<br />Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc. Games or anyone officially involved in producing or managing Riot Games properties.
<br />Riot Games, and all associated properties are trademarks or registered trademarks of
Riot Games, Inc.
</p> </p>
<div class="flex items-center justify-between px-6"> <div class="flex items-center justify-between px-6">
<p> <p>
@ -128,7 +130,7 @@
</a> </a>
</p> </p>
<a <a
class="relative text-sm github" class="github relative text-sm"
href="https://github.com/vkaelin/LeagueStats" href="https://github.com/vkaelin/LeagueStats"
target="_blank" target="_blank"
> >

View file

@ -1,6 +1,6 @@
<template> <template>
<transition name="slide"> <transition name="slide">
<div v-if="data.status === 'loaded' && detailsOpen" class="bg-blue-800 rounded-b-lg"> <div v-if="data.status === 'loaded' && detailsOpen" class="rounded-b-lg bg-blue-800">
<DetailedMatchTeam <DetailedMatchTeam
:data="allyTeam" :data="allyTeam"
:all-players="[...allyTeam.players, ...enemyTeam.players]" :all-players="[...allyTeam.players, ...enemyTeam.players]"
@ -28,7 +28,7 @@
/> />
</div> </div>
<div v-else-if="data.status === 'loading' && detailsOpen"> <div v-else-if="data.status === 'loading' && detailsOpen">
<div class="py-5 bg-blue-800 rounded-b-lg"> <div class="rounded-b-lg bg-blue-800 py-5">
<CubeLoader /> <CubeLoader />
</div> </div>
</div> </div>
@ -52,30 +52,34 @@ export default {
props: { props: {
data: { data: {
type: Object, type: Object,
required: true required: true,
}, },
detailsOpen: { detailsOpen: {
type: Boolean, type: Boolean,
required: true required: true,
} },
}, },
computed: { computed: {
allyTeam() { allyTeam() {
return this.data.blueTeam.players.some(p => p.summonerId === this.account.id) ? this.data.blueTeam : this.data.redTeam return this.data.blueTeam.players.some((p) => p.summonerId === this.account.id)
? this.data.blueTeam
: this.data.redTeam
}, },
enemyTeam() { enemyTeam() {
return this.data.blueTeam.players.some(p => p.summonerId === this.account.id) ? this.data.redTeam : this.data.blueTeam return this.data.blueTeam.players.some((p) => p.summonerId === this.account.id)
? this.data.redTeam
: this.data.blueTeam
}, },
...mapState({ ...mapState({
account: state => state.summoner.basic.account, account: (state) => state.summoner.basic.account,
percentSettings: state => state.settings.percent percentSettings: (state) => state.settings.percent,
}), }),
}, },
methods: { methods: {
...mapActions('settings', ['updatePercent']), ...mapActions('settings', ['updatePercent']),
} },
} }
</script> </script>

View file

@ -4,54 +4,53 @@
<Tooltip <Tooltip
v-for="ban in team.bans" v-for="ban in team.bans"
:key="'ban-' + ban.pickTurn" :key="'ban-' + ban.pickTurn"
:class="{'ml-2': ban.pickTurn !== 6 && ban.pickTurn !== 1}" :class="{ 'ml-2': ban.pickTurn !== 6 && ban.pickTurn !== 1 }"
class="inline-block" class="inline-block"
> >
<template #trigger> <template #trigger>
<div <div
:class="[allyTeam ? 'ban-blue border-teal-500' : 'ban-red border-red-500']" :class="[allyTeam ? 'ban-blue border-teal-500' : 'ban-red border-red-500']"
class="relative border-2 rounded-full cursor-pointer ban" class="ban relative cursor-pointer rounded-full border-2"
> >
<div <div
:style="[ban.champion.id ? {backgroundImage: `url('${ban.champion.icon}')`} : '']" :style="[ban.champion.id ? { backgroundImage: `url('${ban.champion.icon}')` } : '']"
class="w-6 h-6 bg-center bg-cover rounded-full ban-img bg-blue-1000" class="ban-img h-6 w-6 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div <div
:class="[textLightColor, bgColor]" :class="[textLightColor, bgColor]"
class="absolute flex items-center justify-center w-4 h-4 text-xs font-bold rounded-full ban-order" class="ban-order absolute flex h-4 w-4 items-center justify-center rounded-full text-xs font-bold"
>{{ ban.pickTurn }}</div> >
{{ ban.pickTurn }}
</div>
</div> </div>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-xs leading-tight text-center text-white select-none"> <div class="select-none px-2 text-center text-xs leading-tight text-white">
<div>{{ ban.champion.id ? ban.champion.name : 'No ban' }}</div> <div>{{ ban.champion.id ? ban.champion.name : 'No ban' }}</div>
</div> </div>
</template> </template>
</Tooltip> </Tooltip>
</div> </div>
<div <div
:class="allyTeam ? 'text-left' : 'text-right flex-row-reverse'" :class="allyTeam ? 'text-left' : 'flex-row-reverse text-right'"
class="flex mt-2 leading-tight" class="mt-2 flex leading-tight"
> >
<div> <div>
<div <div :class="textColor" class="text-sm font-medium">
:class="textColor" {{ `${team.teamStats.kills}/${team.teamStats.deaths}/${team.teamStats.assists}` }}
class="text-sm font-medium" </div>
>{{ `${team.teamStats.kills}/${team.teamStats.deaths}/${team.teamStats.assists}` }}</div>
<div class="text-xs text-white">K / D / A</div> <div class="text-xs text-white">K / D / A</div>
</div> </div>
<div :class="allyTeam ? 'ml-3' : 'mr-3'"> <div :class="allyTeam ? 'ml-3' : 'mr-3'">
<div <div :class="textColor" class="text-sm font-medium">
:class="textColor" {{ +(team.teamStats.gold / 1000).toFixed(1) + 'k' }}
class="text-sm font-medium" </div>
>{{ +(team.teamStats.gold / 1000).toFixed(1) + 'k' }}</div>
<div class="text-xs text-white">Gold</div> <div class="text-xs text-white">Gold</div>
</div> </div>
<div :class="allyTeam ? 'ml-3' : 'mr-3'"> <div :class="allyTeam ? 'ml-3' : 'mr-3'">
<div <div :class="textColor" class="text-sm font-medium">
:class="textColor" {{ +(team.teamStats.dmgChamp / 1000).toFixed(1) + 'k' }}
class="text-sm font-medium" </div>
>{{ +(team.teamStats.dmgChamp / 1000).toFixed(1) + 'k' }}</div>
<div class="text-xs text-white">Dmg</div> <div class="text-xs text-white">Dmg</div>
</div> </div>
<div :class="allyTeam ? 'ml-3' : 'mr-3'" class="flex flex-col justify-end"> <div :class="allyTeam ? 'ml-3' : 'mr-3'" class="flex flex-col justify-end">
@ -83,12 +82,12 @@ export default {
props: { props: {
team: { team: {
type: Object, type: Object,
required: true required: true,
}, },
allyTeam: { allyTeam: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
computed: { computed: {
@ -100,7 +99,7 @@ export default {
}, },
bgColor() { bgColor() {
return this.allyTeam ? 'bg-teal-500' : 'bg-red-500' return this.allyTeam ? 'bg-teal-500' : 'bg-red-500'
} },
} },
} }
</script> </script>

View file

@ -1,91 +1,81 @@
<template> <template>
<table <table
:class="[{ 'rounded-b-lg overflow-hidden': !allyTeam }, data.result]" :class="[{ 'overflow-hidden rounded-b-lg': !allyTeam }, data.result]"
class="w-full table-fixed" class="w-full table-fixed"
> >
<thead class="leading-none heading-detailed"> <thead class="heading-detailed leading-none">
<tr <tr
:style="getHeadingColor(data.result)" :style="getHeadingColor(data.result)"
class="relative font-semibold text-blue-200 heading-row" class="heading-row relative font-semibold text-blue-200"
> >
<th class="py-5 w-players"> <th class="w-players py-5">
<div class="flex justify-between"> <div class="flex justify-between">
<span <span :class="allyTeam ? 'text-teal-400' : 'text-red-400'" class="pl-2"
:class="allyTeam ? 'text-teal-400' : 'text-red-400'" >{{ allyTeam ? 'Ally' : 'Enemy' }} Team</span
class="pl-2" >
>{{ allyTeam ? "Ally" : "Enemy" }} Team</span>
<div <div
v-if="data.result === 'Win'" v-if="data.result === 'Win'"
:class="allyTeam ? 'text-teal-400' : 'text-red-400'" :class="allyTeam ? 'text-teal-400' : 'text-red-400'"
class="flex pr-2" class="flex pr-2"
> >
<svg class="items-center w-4 h-4"> <svg class="h-4 w-4 items-center">
<use xlink:href="#award" /> <use xlink:href="#award" />
</svg> </svg>
<span class="ml-2px">VICTORY</span> <span class="ml-0.5">VICTORY</span>
</div> </div>
</div> </div>
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-kda">K</th> <th class="w-kda px-2 py-5 text-sm font-medium">K</th>
<th class="px-2 py-5 text-sm font-medium w-kda">D</th> <th class="w-kda px-2 py-5 text-sm font-medium">D</th>
<th class="px-2 py-5 text-sm font-medium w-kda">A</th> <th class="w-kda px-2 py-5 text-sm font-medium">A</th>
<th class="px-2 py-5 text-sm font-medium w-minions"> <th class="w-minions px-2 py-5 text-sm font-medium">
{{ statsFormat === "stats" ? "Cs" : "Cs/m" }} {{ statsFormat === 'stats' ? 'Cs' : 'Cs/m' }}
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-vision"> <th class="w-vision px-2 py-5 text-sm font-medium">
{{ statsFormat === "stats" ? "Vs" : "Vs/m" }} {{ statsFormat === 'stats' ? 'Vs' : 'Vs/m' }}
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-gold-dmg-kp">Gold</th> <th class="w-gold-dmg-kp px-2 py-5 text-sm font-medium">Gold</th>
<th class="px-2 py-5 text-sm font-medium w-gold-dmg-kp"> <th class="w-gold-dmg-kp px-2 py-5 text-sm font-medium">
Dmg Dmg
<br />champ <br />champ
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-gold-dmg-kp"> <th class="w-gold-dmg-kp px-2 py-5 text-sm font-medium">
Dmg Dmg
<br />obj <br />obj
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-gold-dmg-kp"> <th class="w-gold-dmg-kp px-2 py-5 text-sm font-medium">
Dmg Dmg
<br />taken <br />taken
</th> </th>
<th class="px-2 py-5 text-sm font-medium w-gold-dmg-kp">KP</th> <th class="w-gold-dmg-kp px-2 py-5 text-sm font-medium">KP</th>
</tr> </tr>
</thead> </thead>
<tbody <tbody :class="{ 'border-b border-blue-700': allyTeam }" class="leading-none">
:class="{ 'border-b border-blue-700': allyTeam }"
class="leading-none"
>
<tr v-for="(player, index) in data.players" :key="player.name + index"> <tr v-for="(player, index) in data.players" :key="player.name + index">
<td class="py-2 border-r border-blue-700"> <td class="border-r border-blue-700 py-2">
<div class="flex justify-between px-1"> <div class="flex justify-between px-1">
<div class="flex"> <div class="flex">
<div class="flex items-center"> <div class="flex items-center">
<div <div
v-if="player.role !== 'NONE'" v-if="player.role !== 'NONE'"
:style="{ :style="{
backgroundImage: `url(${require('@/assets/img/roles/' + backgroundImage: `url(${'/img/roles/' + player.role + '.png'})`,
player.role +
'.png')})`,
}" }"
class="w-4 h-4 bg-center bg-cover" class="h-4 w-4 bg-cover bg-center"
></div> ></div>
</div> </div>
<div <div
:style="{ backgroundImage: `url('${player.champion.icon}')` }" :style="{ backgroundImage: `url('${player.champion.icon}')` }"
class="relative w-8 h-8 ml-2 bg-center bg-cover rounded-full bg-blue-1000" class="relative ml-2 h-8 w-8 rounded-full bg-blue-1000 bg-cover bg-center"
> >
<div <div
:class=" :class="allyTeam ? 'bg-teal-500 text-teal-100' : 'bg-red-500 text-red-100'"
allyTeam class="level-position absolute bottom-0 flex h-4 w-4 items-center justify-center rounded-full text-xxs"
? 'bg-teal-500 text-teal-100'
: 'bg-red-500 text-red-100'
"
class="absolute bottom-0 flex items-center justify-center w-4 h-4 rounded-full level-position text-xxs"
> >
<span>{{ player.level }}</span> <span>{{ player.level }}</span>
</div> </div>
</div> </div>
<div class="flex flex-col justify-around ml-1"> <div class="ml-1 flex flex-col justify-around">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<div <div
@ -95,18 +85,16 @@
})`, })`,
}" }"
:class="{ 'cursor-pointer': player.summonerSpell1 }" :class="{ 'cursor-pointer': player.summonerSpell1 }"
class="w-4 h-4 bg-center bg-cover rounded-md bg-blue-1000" class="h-4 w-4 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
</template> </template>
<template v-if="player.summonerSpell1" #default> <template v-if="player.summonerSpell1" #default>
<div <div class="flex max-w-sm select-none p-2 text-left text-xs text-white">
class="flex max-w-sm p-2 text-xs text-left text-white select-none"
>
<div <div
:style="{ :style="{
backgroundImage: `url('${player.summonerSpell1.icon}')`, backgroundImage: `url('${player.summonerSpell1.icon}')`,
}" }"
class="flex-shrink-0 w-12 h-12 ml-1 bg-center bg-cover rounded-md bg-blue-1000" class="ml-1 h-12 w-12 flex-shrink-0 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2 leading-tight"> <div class="ml-2 leading-tight">
<div class="text-base leading-none"> <div class="text-base leading-none">
@ -128,18 +116,16 @@
})`, })`,
}" }"
:class="{ 'cursor-pointer': player.summonerSpell2 }" :class="{ 'cursor-pointer': player.summonerSpell2 }"
class="w-4 h-4 bg-center bg-cover rounded-md bg-blue-1000" class="h-4 w-4 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
</template> </template>
<template v-if="player.summonerSpell2" #default> <template v-if="player.summonerSpell2" #default>
<div <div class="flex max-w-sm select-none p-2 text-left text-xs text-white">
class="flex max-w-sm p-2 text-xs text-left text-white select-none"
>
<div <div
:style="{ :style="{
backgroundImage: `url('${player.summonerSpell2.icon}')`, backgroundImage: `url('${player.summonerSpell2.icon}')`,
}" }"
class="flex-shrink-0 w-12 h-12 ml-1 bg-center bg-cover rounded-md bg-blue-1000" class="ml-1 h-12 w-12 flex-shrink-0 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2 leading-tight"> <div class="ml-2 leading-tight">
<div class="text-base leading-none"> <div class="text-base leading-none">
@ -158,42 +144,38 @@
<div <div
@click="selectRunes(player)" @click="selectRunes(player)"
:class="{ 'cursor-pointer': player.perks }" :class="{ 'cursor-pointer': player.perks }"
class="flex flex-col justify-around cursor-pointer ml-2px" class="ml-0.5 flex cursor-pointer flex-col justify-around"
> >
<div <div
:style="[ :style="[
player.primaryRune player.primaryRune
? { ? {
background: `url(${player.primaryRune}) center/cover`, background: `url(${player.primaryRune}) center/cover`,
} }
: '', : '',
]" ]"
class="w-4 h-4 rounded-md bg-blue-1000" class="h-4 w-4 rounded-md bg-blue-1000"
></div> ></div>
<div <div
:style="[ :style="[
player.secondaryRune player.secondaryRune
? { ? {
background: `url(${player.secondaryRune}) center/cover`, background: `url(${player.secondaryRune}) center/cover`,
} }
: '', : '',
]" ]"
class="w-4 h-4 rounded-md bg-blue-1000" class="h-4 w-4 rounded-md bg-blue-1000"
></div> ></div>
</div> </div>
</template> </template>
<template v-if="player.perks" #default> <template v-if="player.perks" #default>
<div <div class="select-none px-2 text-center text-sm leading-relaxed text-white">
class="px-2 text-sm leading-relaxed text-center text-white select-none"
>
<p>Click to display</p> <p>Click to display</p>
<p class="font-bold text-teal-400">full runes</p> <p class="font-bold text-teal-400">full runes</p>
</div> </div>
</template> </template>
</Tooltip> </Tooltip>
<div <div class="ml-1 flex flex-col items-start justify-center leading-none">
class="flex flex-col items-start justify-center ml-1 leading-none"
>
<router-link <router-link
v-if="player.summonerSpell1" v-if="player.summonerSpell1"
:to="{ :to="{
@ -201,37 +183,35 @@
params: { region: $route.params.region, name: player.name }, params: { region: $route.params.region, name: player.name },
}" }"
:class="{ :class="{
'font-semibold text-yellow-400': 'font-semibold text-yellow-400': account.id === player.summonerId,
account.id === player.summonerId,
}" }"
class="overflow-hidden text-xs text-left text-white whitespace-no-wrap w-22 text-overflow hover:text-blue-200" class="text-overflow w-[5.5rem] overflow-hidden whitespace-nowrap text-left text-xs text-white hover:text-blue-200"
>{{ player.name }}</router-link> >{{ player.name }}</router-link
>
<div <div
v-else v-else
class="overflow-hidden text-xs text-left text-white whitespace-no-wrap w-22 text-overflow" class="text-overflow w-[5.5rem] overflow-hidden whitespace-nowrap text-left text-xs text-white"
> >
{{ player.name }} {{ player.name }}
</div> </div>
<div class="text-teal-500 text-xxs"> <div class="text-xxs text-teal-500">
{{ player.champion.name }} {{ player.champion.name }}
</div> </div>
</div> </div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<div v-if="player.rank"> <div v-if="player.rank">
<svg class="w-5 h-5 ml-auto"> <svg class="ml-auto h-5 w-5">
<use <use :xlink:href="`#rank-${player.rank.tier.toLowerCase()}`" />
:xlink:href="`#rank-${player.rank.tier.toLowerCase()}`"
/>
</svg> </svg>
<div class="text-blue-300 text-xxs"> <div class="text-xxs text-blue-300">
{{ player.rank.shortName }} {{ player.rank.shortName }}
</div> </div>
</div> </div>
<div v-else-if="!ranksLoaded"> <div v-else-if="!ranksLoaded">
<DotsLoader width="30px" dot-width="10px" /> <DotsLoader width="30px" dot-width="10px" />
</div> </div>
<div v-else class="w-5 h-5"> <div v-else class="h-5 w-5">
<div class="-mt-1 text-2xl text-blue-300">-</div> <div class="-mt-1 text-2xl text-blue-300">-</div>
</div> </div>
<MatchItems :items="player.items" :one-row="true" /> <MatchItems :items="player.items" :one-row="true" />
@ -352,8 +332,8 @@ export default {
}, },
ranksLoaded: { ranksLoaded: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
computed: { computed: {
@ -369,18 +349,14 @@ export default {
methods: { methods: {
bgColor(player, stats) { bgColor(player, stats) {
const value = parseFloat(player.stats[stats]) const value = parseFloat(player.stats[stats])
const biggestValue = Math.max( const biggestValue = Math.max(...this.allPlayers.map((p) => parseFloat(p.stats[stats])), 0)
...this.allPlayers.map((p) => parseFloat(p.stats[stats])),
0
)
const opacity = (value / biggestValue).toFixed(2) const opacity = (value / biggestValue).toFixed(2)
const biggestValueStyle = {} const biggestValueStyle = {}
if (value === biggestValue && value !== 0) { if (value === biggestValue && value !== 0) {
biggestValueStyle.boxShadow = 'rgba(181, 160, 122, 0.5) 0px 0px 10px' biggestValueStyle.boxShadow = 'rgba(181, 160, 122, 0.5) 0px 0px 10px'
biggestValueStyle.border = '2px solid' biggestValueStyle.border = '2px solid'
biggestValueStyle.borderImageSlice = '1' biggestValueStyle.borderImageSlice = '1'
biggestValueStyle.borderImageSource = biggestValueStyle.borderImageSource = 'linear-gradient(to top, #edb457, #f9e9ce)'
'linear-gradient(to top, #edb457, #f9e9ce)'
biggestValueStyle.borderCollapse = 'separate' biggestValueStyle.borderCollapse = 'separate'
} }
@ -419,9 +395,9 @@ export default {
return return
} }
this.displayOrHideRunes(player.perks) this.displayRunes(player.perks)
}, },
...mapActions('cdragon', ['displayOrHideRunes']), ...mapActions('cdragon', ['displayRunes']),
}, },
} }
</script> </script>
@ -433,19 +409,18 @@ export default {
} }
.heading-row th:first-child:before { .heading-row th:first-child:before {
content: ""; content: '';
position: absolute; position: absolute;
z-index: -10; z-index: -10;
top: 0; top: 0;
left: 0; left: 0;
height: 67px; height: 67px;
width: 884px; width: 884px;
background-image: var(--bg-img), background-image: var(--bg-img), linear-gradient(#2a4365 0%, #2b4c77 55%, #235a93 100%);
linear-gradient(#2a4365 0%, #2b4c77 55%, #235a93 100%);
} }
.heading-row th:first-child:after { .heading-row th:first-child:after {
content: ""; content: '';
position: absolute; position: absolute;
right: -1px; right: -1px;
top: 0; top: 0;

View file

@ -1,16 +1,13 @@
<template> <template>
<div class="flex ml-4 overflow-hidden text-sm rounded-lg"> <div class="ml-4 flex overflow-hidden rounded-lg text-sm">
<div class="relative flex justify-between w-full overflow-hidden bg-blue-800 rounded-lg"> <div class="relative flex w-full justify-between overflow-hidden rounded-lg bg-blue-800">
<div class="absolute flex flex-col items-center justify-between h-full horizontal-center"> <div class="horizontal-center absolute flex h-full flex-col items-center justify-between">
<div class="text-base leading-loose text-blue-200">{{ gamemode.name }}</div> <div class="text-base leading-loose text-blue-200">{{ gamemode.name }}</div>
<div class="flex flex-col text-2xl font-bold leading-none vs"> <div class="vs flex flex-col text-2xl font-bold leading-none">
<span>V</span> <span>V</span>
<span class="ml-4 -mt-3">S</span> <span class="-mt-3 ml-4">S</span>
</div> </div>
<div <div :class="{ 'w-10': displayStartTime !== 'Not started yet' }" class="pb-2 text-blue-200">
:class="{'w-10': displayStartTime !== 'Not started yet'}"
class="pb-2 text-blue-200"
>
{{ displayStartTime }} {{ displayStartTime }}
</div> </div>
</div> </div>
@ -22,15 +19,21 @@
class="flex items-center px-5 py-1 leading-loose" class="flex items-center px-5 py-1 leading-loose"
> >
<div <div
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${ally.championId}.png')`}" :style="{
class="w-6 h-6 bg-center bg-cover rounded-full bg-blue-1000" backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${ally.championId}.png')`,
}"
class="h-6 w-6 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<router-link <router-link
v-if="!ally.bot" v-if="!ally.bot"
:to="{ name: 'summoner', params: { region: $route.params.region, name: ally.summonerName }}" :to="{
name: 'summoner',
params: { region: $route.params.region, name: ally.summonerName },
}"
:class="[ally.summonerId === account.id ? 'text-white' : 'text-blue-200']" :class="[ally.summonerId === account.id ? 'text-white' : 'text-blue-200']"
class="relative ml-2 hover:text-white" class="relative ml-2 hover:text-white"
>{{ ally.summonerName }}</router-link> >{{ ally.summonerName }}</router-link
>
</li> </li>
</ul> </ul>
<ul class="w-1/2 text-right"> <ul class="w-1/2 text-right">
@ -42,22 +45,31 @@
> >
<router-link <router-link
v-if="!enemy.bot" v-if="!enemy.bot"
:to="{ name: 'summoner', params: { region: $route.params.region, name: enemy.summonerName }}" :to="{
name: 'summoner',
params: { region: $route.params.region, name: enemy.summonerName },
}"
class="relative text-red-200 hover:text-white" class="relative text-red-200 hover:text-white"
>{{ enemy.summonerName }}</router-link> >{{ enemy.summonerName }}</router-link
>
<div <div
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${enemy.championId}.png')`}" :style="{
class="w-6 h-6 ml-2 bg-center bg-cover rounded-full bg-blue-1000" backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${enemy.championId}.png')`,
}"
class="ml-2 h-6 w-6 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
</li> </li>
</ul> </ul>
</div> </div>
<router-link <router-link
:to="{ name: 'summonerLive', params: { region: $route.params.region, name: $route.params.name }}" :to="{
class="flex items-center pl-6 pr-4 -ml-2 text-base text-blue-200 cursor-pointer live-game-link bg-gradient-x hover:bg-blue-800 hover:text-blue-100" name: 'summonerLive',
params: { region: $route.params.region, name: $route.params.name },
}"
class="live-game-link bg-gradient-x -ml-2 flex cursor-pointer items-center pl-6 pr-4 text-base text-blue-200 hover:bg-blue-800 hover:text-blue-100"
> >
<div class="-mt-2px">more</div> <div class="-mt-0.5">more</div>
<svg class="w-4 h-4 ml-1 transition-transform duration-200 ease-in-out transform"> <svg class="ml-1 h-4 w-4 transform transition-transform duration-200 ease-in-out">
<use xlink:href="#arrow-right" /> <use xlink:href="#arrow-right" />
</svg> </svg>
</router-link> </router-link>
@ -74,43 +86,28 @@ export default {
<style scoped> <style scoped>
.accent-ally { .accent-ally {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(49, 130, 206, 0.7) 0%, rgba(44, 82, 130, 0) 100%);
90deg,
rgba(49, 130, 206, 0.7) 0%,
rgba(44, 82, 130, 0) 100%
);
} }
.ally { .ally {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(49, 130, 206, 0.3) 0%, rgba(44, 82, 130, 0) 90%);
90deg,
rgba(49, 130, 206, 0.3) 0%,
rgba(44, 82, 130, 0) 90%
);
} }
.accent-enemy { .accent-enemy {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(44, 82, 130, 0) 0%, rgba(140, 0, 0, 0.4) 100%);
90deg,
rgba(44, 82, 130, 0) 0%,
rgba(140, 0, 0, 0.4) 100%
);
} }
.enemy { .enemy {
background-image: linear-gradient( background-image: linear-gradient(90deg, rgba(44, 82, 130, 0) 10%, rgba(140, 0, 0, 0.3) 100%);
90deg,
rgba(44, 82, 130, 0) 10%,
rgba(140, 0, 0, 0.3) 100%
);
} }
.vs { .vs {
text-shadow: 3px 2px 0px rgba(49, 130, 206, 0.8), text-shadow:
3px 2px 0px rgba(49, 130, 206, 0.8),
-3px 2px 0px rgba(229, 62, 62, 0.8); -3px 2px 0px rgba(229, 62, 62, 0.8);
} }
.live-game-link:hover svg { .live-game-link:hover svg {
@apply translate-x-1 @apply translate-x-1;
} }
</style> </style>

View file

@ -3,67 +3,73 @@
<Ripple <Ripple
@click.native="displayDetails" @click.native="displayDetails"
color="rgba(43, 108, 176, 0.7)" color="rgba(43, 108, 176, 0.7)"
:class="[data.result, showDetails ? 'rounded-t-lg' : 'rounded-lg', {'mt-4': indexMatch !== 0 }]" :class="[
class="relative text-base text-white bg-blue-800 cursor-pointer match hover:shadow-xl" data.result,
showDetails ? 'rounded-t-lg' : 'rounded-lg',
{ 'mt-4': indexMatch !== 0 },
]"
class="match relative cursor-pointer bg-blue-800 text-base text-white hover:shadow-xl"
> >
<div class="relative flex flex-wrap px-5 py-3"> <div class="relative flex flex-wrap px-5 py-3">
<div <div
v-if="data.newMatch" v-if="data.newMatch"
class="absolute top-0 right-0 px-2 rounded-full new-match text-xxs" class="new-match absolute right-0 top-0 rounded-full px-2 text-xxs"
style="margin: 0.35rem 0.35rem 0 0; background-color: rgba(99,179,237, .2);" style="margin: 0.35rem 0.35rem 0 0; background-color: rgba(99, 179, 237, 0.2)"
>New</div> >
<div class="w-4/12 text-left first"> New
</div>
<div class="first w-4/12 text-left">
<div> <div>
<div <div class="h-6 text-lg font-extrabold uppercase leading-none text-teal-500">
class="h-6 text-lg font-extrabold leading-none text-teal-500 uppercase" {{ data.champion.name }}
>{{ data.champion.name }}</div> </div>
<div class="flex"> <div class="flex">
<div class="flex flex-col items-center justify-end"> <div class="flex flex-col items-center justify-end">
<div <div
v-if="data.role !== 'NONE'" v-if="data.role !== 'NONE'"
:style="{backgroundImage: `url(${require('@/assets/img/roles/' + data.role + '.png')})`}" :style="{ backgroundImage: `url(${'/img/roles/' + data.role + '.png'})` }"
class="w-10 h-10 bg-center bg-cover" class="h-10 w-10 bg-cover bg-center"
></div> ></div>
<div <div class="w-10 text-center text-xs font-extrabold text-teal-500">
class="w-10 text-xs font-extrabold text-center text-teal-500" LVL {{ data.level }}
>LVL {{ data.level }}</div> </div>
</div> </div>
<div <div
:style="{backgroundImage: `url('${data.champion.icon}')`}" :style="{ backgroundImage: `url('${data.champion.icon}')` }"
class="w-16 h-16 ml-2 rounded-lg crop-champion bg-blue-1000" class="crop-champion ml-2 h-16 w-16 rounded-lg bg-blue-1000"
></div> ></div>
<div class="flex flex-col justify-around ml-2"> <div class="ml-2 flex flex-col justify-around">
<div <div
v-if="data.summonerSpell1" v-if="data.summonerSpell1"
:style="{backgroundImage: `url(${data.summonerSpell1.icon})`}" :style="{ backgroundImage: `url(${data.summonerSpell1.icon})` }"
class="w-6 h-6 bg-center bg-cover rounded-md bg-blue-1000" class="h-6 w-6 rounded-md bg-blue-1000 bg-cover bg-center"
></div>
<div
v-else
class="w-6 h-6 rounded-md bg-blue-1000"
></div> ></div>
<div v-else class="h-6 w-6 rounded-md bg-blue-1000"></div>
<div <div
v-if="data.summonerSpell2" v-if="data.summonerSpell2"
:style="{backgroundImage: `url(${data.summonerSpell2.icon})`}" :style="{ backgroundImage: `url(${data.summonerSpell2.icon})` }"
class="w-6 h-6 bg-center bg-cover rounded-md bg-blue-1000" class="h-6 w-6 rounded-md bg-blue-1000 bg-cover bg-center"
></div>
<div v-else class="h-6 w-6 rounded-md bg-blue-1000"></div>
</div>
<div class="ml-1 flex flex-col justify-around">
<div
:style="[
data.primaryRune ? { background: `url(${data.primaryRune}) center/cover` } : '',
]"
class="h-6 w-6 rounded-md bg-blue-1000"
></div> ></div>
<div <div
v-else :style="[
class="w-6 h-6 rounded-md bg-blue-1000" data.secondaryRune
? { background: `url(${data.secondaryRune}) center/cover` }
: '',
]"
class="h-6 w-6 rounded-md bg-blue-1000"
></div> ></div>
</div> </div>
<div class="flex flex-col justify-around ml-1"> <div class="mx-auto flex flex-col items-center justify-center leading-none">
<div
:style="[data.primaryRune ? {background: `url(${data.primaryRune}) center/cover`} : '']"
class="w-6 h-6 rounded-md bg-blue-1000"
></div>
<div
:style="[data.secondaryRune ? {background: `url(${data.secondaryRune}) center/cover`} : '']"
class="w-6 h-6 rounded-md bg-blue-1000"
></div>
</div>
<div class="flex flex-col items-center justify-center mx-auto leading-none">
<div class="text-xl font-extrabold text-teal-500"> <div class="text-xl font-extrabold text-teal-500">
<span class>{{ data.stats.kills }}</span> <span class>{{ data.stats.kills }}</span>
<span class>/</span> <span class>/</span>
@ -71,24 +77,26 @@
<span class>/</span> <span class>/</span>
<span class>{{ data.stats.assists }}</span> <span class>{{ data.stats.assists }}</span>
</div> </div>
<div <div class="relative z-30 mt-2 text-xs font-extrabold text-white">
class="relative z-30 mt-2 text-xs font-extrabold text-white" {{ data.stats.kda }} KDA
>{{ data.stats.kda }} KDA</div> </div>
</div> </div>
</div> </div>
<div <div
class="relative z-30 flex items-end h-6 text-sm font-extrabold leading-none text-white" class="relative z-30 flex h-6 items-end text-sm font-extrabold leading-none text-white"
>{{ data.gamemode.name }}</div> >
{{ data.gamemode.name }}
</div>
</div> </div>
</div> </div>
<div class="flex items-center w-3/12 py-6 second"> <div class="second flex w-3/12 items-center py-6">
<MatchItems :items="data.items" /> <MatchItems :items="data.items" />
<div class="relative z-30 ml-4 leading-none"> <div class="relative z-30 ml-4 leading-none">
<div class="flex items-center"> <div class="flex items-center">
<svg style="width: 15px; height: 15px;"> <svg style="width: 15px; height: 15px">
<use xlink:href="#creeps" /> <use xlink:href="#creeps" />
</svg> </svg>
<div class="ml-1 text-sm font-bold text-teal-300"> <div class="ml-1 text-sm font-bold text-teal-300">
@ -97,83 +105,98 @@
</div> </div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<svg style="width: 15px; height: 15px;"> <svg style="width: 15px; height: 15px">
<use xlink:href="#gold" /> <use xlink:href="#gold" />
</svg> </svg>
<div class="ml-1 text-sm font-bold gold">{{ data.stats.gold|kilo }}</div> <div class="gold ml-1 text-sm font-bold">{{ data.stats.gold | kilo }}</div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<svg style="width: 15px; height: 15px;"> <svg style="width: 15px; height: 15px">
<use xlink:href="#damage" /> <use xlink:href="#damage" />
</svg> </svg>
<div class="ml-1 text-sm font-bold damage">{{ data.stats.dmgChamp|kilo }}</div> <div class="damage ml-1 text-sm font-bold">{{ data.stats.dmgChamp | kilo }}</div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<svg style="width: 15px; height: 15px;"> <svg style="width: 15px; height: 15px">
<use xlink:href="#kill-participation" /> <use xlink:href="#kill-participation" />
</svg> </svg>
<div class="ml-1 text-sm font-bold kp">{{ data.stats.kp|percent }}</div> <div class="kp ml-1 text-sm font-bold">{{ data.stats.kp | percent }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="flex items-center w-5/12 py-1 third"> <div class="third flex w-5/12 items-center py-1">
<div v-if="data.allyTeam.length > 1"> <div v-if="data.allyTeam.length > 1">
<div <div
v-for="(ally, index) in data.allyTeam" v-for="(ally, index) in data.allyTeam"
:key="'player-' + index" :key="'player-' + index"
class="flex items-center ml-4 leading-none" class="ml-4 flex items-center leading-none"
> >
<router-link <router-link
v-if="ally.account_id !== '0' && account.accountId !== ally.account_id" v-if="ally.account_id !== '0' && account.accountId !== ally.account_id"
@click.native="$event.stopImmediatePropagation()" @click.native="$event.stopImmediatePropagation()"
:to="{ name: 'summoner', params: { region: $route.params.region, name: ally.name }}" :to="{
name: 'summoner',
params: { region: $route.params.region, name: ally.name },
}"
:class="isSummonerProfile(ally.account_id)" :class="isSummonerProfile(ally.account_id)"
class="w-16 overflow-hidden text-xs font-medium text-right whitespace-no-wrap hover:text-white text-overflow" class="text-overflow w-16 overflow-hidden whitespace-nowrap text-right text-xs font-medium hover:text-white"
>{{ ally.name }}</router-link> >{{ ally.name }}</router-link
>
<div <div
v-else v-else
:class="isSummonerProfile(ally.account_id)" :class="isSummonerProfile(ally.account_id)"
class="w-16 overflow-hidden text-xs font-medium text-right whitespace-no-wrap text-overflow" class="text-overflow w-16 overflow-hidden whitespace-nowrap text-right text-xs font-medium"
>{{ ally.name }}</div> >
{{ ally.name }}
</div>
<div <div
:class="index !== 0 ? '-mt-1': ''" :class="index !== 0 ? '-mt-1' : ''"
:style="{backgroundImage: `url('${ally.champion.icon}')`}" :style="{ backgroundImage: `url('${ally.champion.icon}')` }"
class="w-6 h-6 ml-1 overflow-hidden bg-center bg-cover rounded-full bg-blue-1000" class="ml-1 h-6 w-6 overflow-hidden rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div <div
:style="{backgroundImage: data.role !== 'NONE' ? `url(${require('@/assets/img/roles/' + roles[index] + '.png')})` : null}" :style="{
class="w-4 h-4 mx-2 bg-center bg-cover" backgroundImage:
data.role !== 'NONE' ? `url(${'/img/roles/' + roles[index] + '.png'})` : null,
}"
class="mx-2 h-4 w-4 bg-cover bg-center"
></div> ></div>
<div <div
:class="index !== 0 ? '-mt-1' : ''" :class="index !== 0 ? '-mt-1' : ''"
:style="{backgroundImage: `url('${data.enemyTeam[index].champion.icon}')`}" :style="{ backgroundImage: `url('${data.enemyTeam[index].champion.icon}')` }"
class="w-6 h-6 bg-center bg-cover rounded-full bg-blue-1000" class="h-6 w-6 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<router-link <router-link
v-if="data.enemyTeam[index].account_id !== '0'" v-if="data.enemyTeam[index].account_id !== '0'"
@click.native="$event.stopImmediatePropagation()" @click.native="$event.stopImmediatePropagation()"
:to="{ name: 'summoner', params: { region: $route.params.region, name: data.enemyTeam[index].name }}" :to="{
class="w-16 ml-1 overflow-hidden text-xs font-medium text-left text-blue-200 whitespace-no-wrap hover:text-white text-overflow" name: 'summoner',
>{{ data.enemyTeam[index].name }}</router-link> params: { region: $route.params.region, name: data.enemyTeam[index].name },
}"
class="text-overflow ml-1 w-16 overflow-hidden whitespace-nowrap text-left text-xs font-medium text-blue-200 hover:text-white"
>{{ data.enemyTeam[index].name }}</router-link
>
<div <div
v-else v-else
class="w-16 ml-1 overflow-hidden text-xs font-medium text-left text-blue-200 whitespace-no-wrap text-overflow" class="text-overflow ml-1 w-16 overflow-hidden whitespace-nowrap text-left text-xs font-medium text-blue-200"
>{{ data.enemyTeam[index].name }}</div> >
{{ data.enemyTeam[index].name }}
</div>
</div> </div>
</div> </div>
<div class="flex flex-col items-center justify-center ml-auto"> <div class="ml-auto flex flex-col items-center justify-center">
<svg class="w-5 h-5 text-blue-200"> <svg class="h-5 w-5 text-blue-200">
<use xlink:href="#stopwatch" /> <use xlink:href="#stopwatch" />
</svg> </svg>
<div class="text-lg font-medium text-teal-400">{{ (data.time)|secToTime }}</div> <div class="text-lg font-medium text-teal-400">{{ data.time | secToTime }}</div>
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<div class="text-xs font-medium text-white">{{ data.date }}</div> <div class="text-xs font-medium text-white">{{ data.date }}</div>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-xs leading-tight text-center text-white select-none"> <div class="select-none px-2 text-center text-xs leading-tight text-white">
<svg class="w-4 h-4 mx-auto text-teal-400"> <svg class="mx-auto h-4 w-4 text-teal-400">
<use xlink:href="#time" /> <use xlink:href="#time" />
</svg> </svg>
<div class="mt-1">{{ data.fullDate.date }}</div> <div class="mt-1">{{ data.fullDate.date }}</div>
@ -207,24 +230,24 @@ export default {
props: { props: {
data: { data: {
type: Object, type: Object,
required: true required: true,
}, },
indexMatch: { indexMatch: {
type: Number, type: Number,
default: -1, default: -1,
} },
}, },
data() { data() {
return { return {
showDetails: false showDetails: false,
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
account: state => state.summoner.basic.account, account: (state) => state.summoner.basic.account,
roles: state => state.roles roles: (state) => state.roles,
}), }),
...mapGetters('detailedMatch', ['getMatchDetails']), ...mapGetters('detailedMatch', ['getMatchDetails']),
}, },
@ -240,11 +263,11 @@ export default {
isSummonerProfile(account_id) { isSummonerProfile(account_id) {
return { return {
'font-bold text-white': this.account.accountId === account_id, 'font-bold text-white': this.account.accountId === account_id,
'text-blue-200': this.account.accountId !== account_id 'text-blue-200': this.account.accountId !== account_id,
} }
}, },
...mapActions('detailedMatch', ['matchDetails']), ...mapActions('detailedMatch', ['matchDetails']),
} },
} }
</script> </script>

View file

@ -1,48 +1,40 @@
<template> <template>
<div <div :class="oneRow ? 'ml-2 items-center' : 'items-2-rows flex-wrap'" class="flex">
:class="oneRow ? 'ml-2 items-center' : 'items-2-rows flex-wrap'"
class="flex"
>
<Tooltip v-for="(item, index) in items" :key="index"> <Tooltip v-for="(item, index) in items" :key="index">
<template #trigger> <template #trigger>
<div class="relative"> <div class="relative">
<div <div
:style="{ backgroundImage: itemLink(item) }" :style="{ backgroundImage: itemLink(item) }"
:class="[ :class="[
oneRow ? 'ml-2px w-6 h-6' : 'ml-1 w-8 h-8', oneRow ? 'ml-0.5 h-6 w-6' : 'ml-1 h-8 w-8',
{ 'cursor-pointer': item !== null }, { 'cursor-pointer': item !== null },
]" ]"
class="relative z-10 bg-center bg-cover rounded-md bg-blue-1000" class="relative z-10 rounded-md bg-blue-1000 bg-cover bg-center"
> >
<div <div v-if="isMythic(item)" class="mythic-inside h-full w-full rounded-md"></div>
v-if="isMythic(item)"
class="w-full h-full rounded-md mythic-inside"
></div>
</div> </div>
<div <div
v-if="isMythic(item)" v-if="isMythic(item)"
class="absolute rounded-md mythic" class="mythic absolute rounded-md"
:class="oneRow ? 'mythic-sm' : 'mythic-xl'" :class="oneRow ? 'mythic-sm' : 'mythic-xl'"
></div> ></div>
</div> </div>
</template> </template>
<template v-if="item !== null" #default> <template v-if="item !== null" #default>
<div class="flex max-w-md p-2 text-xs text-left text-white select-none"> <div class="flex max-w-md select-none p-2 text-left text-xs text-white">
<div <div
:style="{ backgroundImage: itemLink(item) }" :style="{ backgroundImage: itemLink(item) }"
class="flex-shrink-0 w-12 h-12 ml-1 bg-center bg-cover rounded-md bg-blue-1000" class="ml-1 h-12 w-12 flex-shrink-0 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2 leading-none"> <div class="ml-2 leading-none">
<div class="text-base">{{ itemName(item.name) }}</div> <div class="text-base">{{ itemName(item.name) }}</div>
<div class="mt-1"> <div class="mt-1">
<span class="text-blue-200">Price:</span> <span class="text-blue-200">Price:</span>
<span class="ml-1 text-sm font-semibold text-yellow-500">{{ <span class="ml-1 text-sm font-semibold text-yellow-500">{{ item.price }}</span>
item.price
}}</span>
</div> </div>
<div <div
v-html="item.description" v-html="item.description"
class="mt-1 font-light text-blue-200 item-description" class="item-description mt-1 font-light text-blue-200"
></div> ></div>
</div> </div>
</div> </div>
@ -56,18 +48,18 @@ import Tooltip from '@/components/Common/Tooltip.vue'
export default { export default {
components: { components: {
Tooltip Tooltip,
}, },
props: { props: {
oneRow: { oneRow: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
items: { items: {
type: Array, type: Array,
required: true required: true,
} },
}, },
methods: { methods: {
@ -81,14 +73,16 @@ export default {
// Fix to still make work the old items links (before season 11) // Fix to still make work the old items links (before season 11)
const originalUrl = item.image const originalUrl = item.image
const newUrl = originalUrl.includes('/global/default/assets/items/') ? originalUrl : originalUrl.replace('latest', '10.22') const newUrl = originalUrl.includes('/global/default/assets/items/')
? originalUrl
: originalUrl.replace('latest', '10.22')
return `url('${newUrl}')` return `url('${newUrl}')`
}, },
itemName(name) { itemName(name) {
// Remove placeholders in item names (e.g.: for Ornn items) // Remove placeholders in item names (e.g.: for Ornn items)
return name.replace(/%[^%]*%/, '') return name.replace(/%[^%]*%/, '')
} },
} },
} }
</script> </script>
@ -126,7 +120,7 @@ export default {
} }
.item-description >>> stats { .item-description >>> stats {
@apply text-white leading-tight; @apply leading-tight text-white;
} }
.item-description >>> br + br { .item-description >>> br + br {
@ -138,21 +132,21 @@ export default {
} }
.item-description >>> li { .item-description >>> li {
@apply block mt-2; @apply mt-2 block;
} }
.item-description >>> passive { .item-description >>> passive {
@apply text-white font-normal; @apply font-normal text-white;
} }
.item-description >>> active { .item-description >>> active {
@apply inline-block text-white font-bold mt-2; @apply mt-2 inline-block font-bold text-white;
} }
.item-description >>> unique, .item-description >>> unique,
.item-description >>> li > passive:first-child, .item-description >>> li > passive:first-child,
.item-description >>> rarityMythic { .item-description >>> rarityMythic {
@apply text-white font-bold block mt-2; @apply mt-2 block font-bold text-white;
} }
.item-description >>> font { .item-description >>> font {
@ -160,10 +154,10 @@ export default {
} }
.item-description >>> rules { .item-description >>> rules {
@apply inline-block mt-2 text-blue-400 italic; @apply mt-2 inline-block italic text-blue-400;
} }
.item-description >>> rules active { .item-description >>> rules active {
@apply inline text-white font-normal; @apply inline font-normal text-white;
} }
</style> </style>

View file

@ -4,58 +4,44 @@
:style="{ :style="{
backgroundImage: `url('${createCategoryBorderUrl(runeStyle.name)}')`, backgroundImage: `url('${createCategoryBorderUrl(runeStyle.name)}')`,
}" }"
class="flex items-center justify-center w-24 h-24 bg-cover" class="flex h-24 w-24 items-center justify-center bg-cover"
> >
<div <div
:style="{ :style="{
backgroundImage: `url('${createCategoryUrl(runeStyle.name)}')`, backgroundImage: `url('${createCategoryUrl(runeStyle.name)}')`,
}" }"
style="filter: brightness(1.2)" style="filter: brightness(1.2)"
class="w-56 h-56 mt-4 bg-center bg-no-repeat bg-contain" class="mt-4 h-56 w-56 bg-contain bg-center bg-no-repeat"
></div> ></div>
</div> </div>
<div class="mt-24 space-y-4"> <div class="mt-24 space-y-4">
<div <div v-for="(category, index) in slots" :key="`secondary-category-${index}`" class="">
v-for="(category, index) in slots"
:key="`secondary-category-${index}`"
class=""
>
<div class="flex space-x-4"> <div class="flex space-x-4">
<ul v-for="runeId in category" :key="`slot-${runeId}`"> <ul v-for="runeId in category" :key="`slot-${runeId}`">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<li <li
:style="{ :style="{
backgroundImage: `url('${createCDragonAssetUrl( backgroundImage: `url('${createCDragonAssetUrl(runes.perks[runeId].icon)}')`,
runes.perks[runeId].icon
)}')`,
}" }"
:class=" :class="selectedRunes.selected.includes(runeId) ? 'used-rune' : 'not-used-rune'"
selectedRunes.selected.includes(runeId) class="h-12 w-12 cursor-pointer rounded-full border-2 border-gray-700 bg-cover bg-center"
? 'used-rune'
: 'not-used-rune'
"
class="w-12 h-12 bg-center bg-cover border-2 border-gray-700 rounded-full cursor-pointer"
></li> ></li>
</template> </template>
<template #default> <template #default>
<div <div class="flex max-w-md select-none p-2 text-left text-sm text-white">
class="flex max-w-md p-2 text-sm text-left text-white select-none"
>
<div <div
:style="{ :style="{
backgroundImage: `url('${createCDragonAssetUrl( backgroundImage: `url('${createCDragonAssetUrl(runes.perks[runeId].icon)}')`,
runes.perks[runeId].icon
)}')`,
}" }"
class="flex-shrink-0 w-12 h-12 ml-1 bg-center bg-cover rounded-md bg-blue-1000" class="ml-1 h-12 w-12 flex-shrink-0 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2 leading-none"> <div class="ml-2 leading-none">
<div class="text-base">{{ runes.perks[runeId].name }}</div> <div class="text-base">{{ runes.perks[runeId].name }}</div>
<div <div
v-html="runes.perks[runeId].desc" v-html="runes.perks[runeId].desc"
class="mt-3 font-light leading-tight text-blue-200 rune-description" class="rune-description mt-3 font-light leading-tight text-blue-200"
></div> ></div>
</div> </div>
</div> </div>
@ -63,53 +49,38 @@
</Tooltip> </Tooltip>
</ul> </ul>
</div> </div>
<div <div v-if="primary && index == 0" class="mt-4 h-0.5 w-full bg-gray-500 bg-opacity-25"></div>
v-if="primary && index == 0"
class="w-full mt-4 bg-gray-500 bg-opacity-25 h-2px"
></div>
</div> </div>
<div v-if="!primary"> <div v-if="!primary">
<div class="mt-8 space-y-4"> <div class="mt-8 space-y-4">
<div <div v-for="(row, index) in kStats" :key="`row-${index}`" class="flex space-x-8 px-3">
v-for="(row, index) in kStats"
:key="`row-${index}`"
class="flex px-3 space-x-8"
>
<ul v-for="(kStat, i) in row" :key="`${kStat}-${i}`"> <ul v-for="(kStat, i) in row" :key="`${kStat}-${i}`">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<li <li
:style="{ :style="{
backgroundImage: `url('${createCDragonAssetUrl( backgroundImage: `url('${createCDragonAssetUrl(runes.perks[kStat].icon)}')`,
runes.perks[kStat].icon
)}')`,
}" }"
:class=" :class="
selectedRunes.selected[index + 6] === kStat selectedRunes.selected[index + 6] === kStat ? 'used-rune' : 'not-used-rune'
? 'used-rune'
: 'not-used-rune'
" "
class="w-8 h-8 bg-gray-900 bg-center bg-cover border-2 border-gray-700 rounded-full cursor-pointer" class="h-8 w-8 cursor-pointer rounded-full border-2 border-gray-700 bg-gray-900 bg-cover bg-center"
></li> ></li>
</template> </template>
<template #default> <template #default>
<div <div class="flex max-w-md select-none p-2 text-left text-sm text-white">
class="flex max-w-md p-2 text-sm text-left text-white select-none"
>
<div <div
:style="{ :style="{
backgroundImage: `url('${createCDragonAssetUrl( backgroundImage: `url('${createCDragonAssetUrl(runes.perks[kStat].icon)}')`,
runes.perks[kStat].icon
)}')`,
}" }"
class="flex-shrink-0 w-8 h-8 ml-1 bg-center bg-cover rounded-md bg-blue-1000" class="ml-1 h-8 w-8 flex-shrink-0 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2 leading-none"> <div class="ml-2 leading-none">
<div class="text-base">{{ runes.perks[kStat].name }}</div> <div class="text-base">{{ runes.perks[kStat].name }}</div>
<div <div
v-html="runes.perks[kStat].desc" v-html="runes.perks[kStat].desc"
class="mt-3 font-light leading-tight text-blue-200 rune-description" class="rune-description mt-3 font-light leading-tight text-blue-200"
></div> ></div>
</div> </div>
</div> </div>
@ -136,12 +107,12 @@ export default {
props: { props: {
primary: { primary: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
runeStyle: { runeStyle: {
type: Object, type: Object,
required: true required: true,
} },
}, },
computed: { computed: {
@ -149,10 +120,10 @@ export default {
return this.primary ? this.runeStyle.slots : this.runeStyle.slots.slice(1) return this.primary ? this.runeStyle.slots : this.runeStyle.slots.slice(1)
}, },
...mapState({ ...mapState({
kStats: state => state.cdragon.kStats, kStats: (state) => state.cdragon.kStats,
runes: state => state.cdragon.runes, runes: (state) => state.cdragon.runes,
runesOpen: state => state.cdragon.runesOpen, runesOpen: (state) => state.cdragon.runesOpen,
selectedRunes: state => state.cdragon.selectedRunes selectedRunes: (state) => state.cdragon.selectedRunes,
}), }),
}, },
@ -166,7 +137,7 @@ export default {
return `https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-collections/global/default/perks/images/${lower}/icon-${lower[0]}.png` return `https://raw.communitydragon.org/latest/plugins/rcp-fe-lol-collections/global/default/perks/images/${lower}/icon-${lower[0]}.png`
}, },
createCDragonAssetUrl, createCDragonAssetUrl,
} },
} }
</script> </script>

View file

@ -1,9 +1,6 @@
<template> <template>
<transition leave-active-class="duration-300"> <transition leave-active-class="duration-300">
<div <div v-show="runesOpen" class="fixed inset-0 z-50 flex items-center justify-center">
v-show="runesOpen"
class="fixed inset-0 z-50 flex items-center justify-center"
>
<transition <transition
enter-active-class="transition duration-300 ease-out" enter-active-class="transition duration-300 ease-out"
enter-class="transform opacity-0" enter-class="transform opacity-0"
@ -12,11 +9,7 @@
leave-class="transform opacity-100" leave-class="transform opacity-100"
leave-to-class="transform opacity-0" leave-to-class="transform opacity-0"
> >
<div <div v-if="runesOpen" @click="close" class="fixed inset-0 bg-gray-900 bg-opacity-75"></div>
v-if="runesOpen"
@click="close"
class="fixed inset-0 bg-gray-900 bg-opacity-75"
></div>
</transition> </transition>
<transition <transition
@ -29,20 +22,18 @@
> >
<div <div
v-if="runesOpen" v-if="runesOpen"
class="relative overflow-hidden bg-gray-900 rounded-md shadow-lg" class="relative overflow-hidden rounded-md bg-gray-900 shadow-lg"
style="width: 800px; height: 500px" style="width: 800px; height: 500px"
> >
<LazyBackground <LazyBackground
:image-source=" :image-source="`/img/runes/${primaryStyle.name.toLowerCase()}.jpg`"
require(`@/assets/img/runes/${primaryStyle.name.toLowerCase()}.jpg`)
"
image-class="absolute inset-0" image-class="absolute inset-0"
more-backgrounds="linear-gradient(rgba(26, 32, 44, 0.6), rgba(26, 32, 44, 0.8))," more-backgrounds="linear-gradient(rgba(26, 32, 44, 0.6), rgba(26, 32, 44, 0.8)),"
transition-name="fade-fast" transition-name="fade-fast"
style="filter: blur(2px)" style="filter: blur(2px)"
> >
</LazyBackground> </LazyBackground>
<div class="relative flex items-start h-full px-4 py-2"> <div class="relative flex h-full items-start px-4 py-2">
<div class="w-1/2"> <div class="w-1/2">
<RuneStyle :primary="true" :rune-style="primaryStyle" /> <RuneStyle :primary="true" :rune-style="primaryStyle" />
</div> </div>
@ -76,9 +67,9 @@ export default {
return this.runes.perkstyles[this.selectedRunes.secondaryStyle] return this.runes.perkstyles[this.selectedRunes.secondaryStyle]
}, },
...mapState({ ...mapState({
runes: state => state.cdragon.runes, runes: (state) => state.cdragon.runes,
runesOpen: state => state.cdragon.runesOpen, runesOpen: (state) => state.cdragon.runesOpen,
selectedRunes: state => state.cdragon.selectedRunes selectedRunes: (state) => state.cdragon.selectedRunes,
}), }),
}, },
@ -92,15 +83,15 @@ export default {
methods: { methods: {
close() { close() {
this.displayOrHideRunes({}) this.hideRunes({})
}, },
handleEscape(e) { handleEscape(e) {
if (e.key === 'Esc' || e.key === 'Escape') { if (e.key === 'Esc' || e.key === 'Escape') {
this.displayOrHideRunes({}) this.hideRunes({})
} }
}, },
createCDragonAssetUrl, createCDragonAssetUrl,
...mapActions('cdragon', ['displayOrHideRunes']) ...mapActions('cdragon', ['hideRunes']),
} },
} }
</script> </script>

View file

@ -3,11 +3,11 @@
<input <input
v-model="championName" v-model="championName"
@input="search" @input="search"
class="px-2 py-2 pl-10 rounded-lg outline-none input-color focus:bg-blue-1000" class="input-color rounded-lg px-2 py-2 pl-10 outline-none focus:bg-blue-1000"
type="text" type="text"
placeholder="Search Champions" placeholder="Search Champions"
/> />
<svg class="absolute left-0 w-4 h-4 ml-3 vertical-center"> <svg class="vertical-center absolute left-0 ml-3 h-4 w-4">
<use xlink:href="#search" /> <use xlink:href="#search" />
</svg> </svg>
</Ripple> </Ripple>
@ -23,15 +23,15 @@ export default {
data() { data() {
return { return {
championName: '' championName: '',
} }
}, },
methods: { methods: {
search() { search() {
this.$emit('search-champions', this.championName) this.$emit('search-champions', this.championName)
} },
} },
} }
</script> </script>

View file

@ -1,24 +1,28 @@
<template> <template>
<table class="w-full leading-none text-center bg-blue-800 rounded-lg table-fixed"> <table class="w-full table-fixed rounded-lg bg-blue-800 text-center leading-none">
<thead> <thead>
<tr class="text-sm rounded-t-lg select-none heading"> <tr class="heading select-none rounded-t-lg text-sm">
<th <th
@click="sortBy('index')" @click="sortBy('index')"
:class="sortedClasses('index')" :class="sortedClasses('index')"
class="relative px-2 py-4 font-normal rounded-tl-lg cursor-pointer hover:bg-blue-700" class="relative cursor-pointer rounded-tl-lg px-2 py-4 font-normal hover:bg-blue-700"
>rank</th> >
rank
</th>
<th <th
v-for="(heading, index) in headings" v-for="(heading, index) in headings"
:key="`champHeading-${index}`" :key="`champHeading-${index}`"
@click="sortBy(heading.props)" @click="sortBy(heading.props)"
v-html="heading.name" v-html="heading.name"
:class="[ :class="[
{'rounded-tr-lg': index === headings.length - 1, {
'w-name': heading.name === 'Name', 'rounded-tr-lg': index === headings.length - 1,
'w-kda': heading.name === 'KDA'}, 'w-name': heading.name === 'Name',
sortedClasses(heading.props) 'w-kda': heading.name === 'KDA',
},
sortedClasses(heading.props),
]" ]"
class="relative px-2 py-4 font-normal cursor-pointer hover:bg-blue-700" class="relative cursor-pointer px-2 py-4 font-normal hover:bg-blue-700"
></th> ></th>
</tr> </tr>
</thead> </thead>
@ -26,75 +30,69 @@
<tr <tr
v-for="(champion, index) in championsToDisplay" v-for="(champion, index) in championsToDisplay"
:key="champion._id" :key="champion._id"
:class="{'rounded-b-lg': index === championsToDisplay.length - 1}" :class="{ 'rounded-b-lg': index === championsToDisplay.length - 1 }"
> >
<td <td
:class="{'rounded-bl-lg': index === championsToDisplay.length - 1}" :class="{ 'rounded-bl-lg': index === championsToDisplay.length - 1 }"
class="relative px-2 py-3 text-sm text-white bg-blue-800 border-t-table" class="border-t-table relative bg-blue-800 px-2 py-3 text-sm text-white"
>{{ champion.index + 1 }}</td> >
<td class="relative px-2 py-3 text-sm text-white bg-blue-800 border-t-table"> {{ champion.index + 1 }}
</td>
<td class="border-t-table relative bg-blue-800 px-2 py-3 text-sm text-white">
<div class="flex items-center"> <div class="flex items-center">
<div <div
:style="{backgroundImage: `url('${champion.champion.icon}')`}" :style="{ backgroundImage: `url('${champion.champion.icon}')` }"
class="flex-shrink-0 w-6 h-6 bg-center bg-cover rounded-full bg-blue-1000" class="h-6 w-6 flex-shrink-0 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="ml-2">{{ champion.champion.name }}</div> <div class="ml-2">{{ champion.champion.name }}</div>
</div> </div>
</td> </td>
<td <td :style="bgColor(champion, 'winrate')" class="px-2 py-3 text-sm text-white">
:style="bgColor(champion, 'winrate')" {{ champion.winrate | percent }}
class="px-2 py-3 text-sm text-white" </td>
>{{ champion.winrate|percent }}</td> <td :style="bgColor(champion, 'playrate')" class="px-2 py-3 text-sm text-white">
<td {{ champion.playrate | percent }}
:style="bgColor(champion, 'playrate')" </td>
class="px-2 py-3 text-sm text-white" <td :style="bgColor(champion, 'wins')" class="px-2 py-3 text-sm text-white">
>{{ champion.playrate|percent }}</td> {{ champion.wins }}
<td </td>
:style="bgColor(champion, 'wins')" <td :style="bgColor(champion, 'count')" class="px-2 py-3 text-sm text-white">
class="px-2 py-3 text-sm text-white" {{ champion.count }}
>{{ champion.wins }}</td> </td>
<td
:style="bgColor(champion, 'count')"
class="px-2 py-3 text-sm text-white"
>{{ champion.count }}</td>
<td :style="bgColor(champion, 'kda')" class="px-2 py-3 text-sm text-white"> <td :style="bgColor(champion, 'kda')" class="px-2 py-3 text-sm text-white">
<div>{{ champion.kda|round }}</div> <div>{{ champion.kda | round }}</div>
<div class="mt-1 text-blue-200 whitespace-no-wrap text-xxs"> <div class="mt-1 whitespace-nowrap text-xxs text-blue-200">
{{ champion.kills/champion.count|round(1) }} {{ (champion.kills / champion.count) | round(1) }}
/ /
{{ champion.deaths/champion.count|round(1) }} {{ (champion.deaths / champion.count) | round(1) }}
/ /
{{ champion.assists/champion.count|round(1) }} {{ (champion.assists / champion.count) | round(1) }}
</div> </div>
</td> </td>
<td :style="bgColor(champion, 'kp')" class="px-2 py-3 text-sm text-white">
{{ champion.kp | percent }}
</td>
<td :style="bgColor(champion, 'minions')" class="px-2 py-3 text-sm text-white">
{{ champion.minions | round(0) }}
</td>
<td :style="bgColor(champion, 'gold')" class="px-2 py-3 text-sm text-white">
{{ champion.gold | kilo }}
</td>
<td :style="bgColor(champion, 'dmgChamp')" class="px-2 py-3 text-sm text-white">
{{ champion.dmgChamp | kilo }}
</td>
<td :style="bgColor(champion, 'dmgTaken')" class="px-2 py-3 text-sm text-white">
{{ champion.dmgTaken | kilo }}
</td>
<td :style="bgColor(champion, 'gameLength')" class="px-2 py-3 text-sm text-white">
{{ champion.gameLength | secToTime }}
</td>
<td <td
:style="bgColor(champion, 'kp')" :class="{ 'rounded-br-lg': index === championsToDisplay.length - 1 }"
class="px-2 py-3 text-sm text-white"
>{{ champion.kp|percent }}</td>
<td
:style="bgColor(champion, 'minions')"
class="px-2 py-3 text-sm text-white"
>{{ champion.minions|round(0) }}</td>
<td
:style="bgColor(champion, 'gold')"
class="px-2 py-3 text-sm text-white"
>{{ champion.gold|kilo }}</td>
<td
:style="bgColor(champion, 'dmgChamp')"
class="px-2 py-3 text-sm text-white"
>{{ champion.dmgChamp|kilo }}</td>
<td
:style="bgColor(champion, 'dmgTaken')"
class="px-2 py-3 text-sm text-white"
>{{ champion.dmgTaken|kilo }}</td>
<td
:style="bgColor(champion, 'gameLength')"
class="px-2 py-3 text-sm text-white"
>{{ champion.gameLength|secToTime }}</td>
<td
:class="{'rounded-br-lg': index === championsToDisplay.length - 1}"
class="px-2 py-3 text-xs text-white" class="px-2 py-3 text-xs text-white"
>{{ champion.lastPlayed }}</td> >
{{ champion.lastPlayed }}
</td>
</tr> </tr>
</tbody> </tbody>
<tbody v-else> <tbody v-else>
@ -143,16 +141,16 @@ export default {
props: { props: {
champions: { champions: {
type: Array, type: Array,
required: true required: true,
}, },
onlyMostPlayed: { onlyMostPlayed: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
search: { search: {
type: String, type: String,
default: '' default: '',
} },
}, },
data() { data() {
@ -160,66 +158,66 @@ export default {
headings: [ headings: [
{ {
name: 'Name', name: 'Name',
props: 'champion.name' props: 'champion.name',
}, },
{ {
name: 'Win <br> rate', name: 'Win <br> rate',
props: 'winrate' props: 'winrate',
}, },
{ {
name: 'Play <br> rate', name: 'Play <br> rate',
props: 'playrate' props: 'playrate',
}, },
{ {
name: 'Wins', name: 'Wins',
props: 'wins' props: 'wins',
}, },
{ {
name: 'Plays', name: 'Plays',
props: 'count' props: 'count',
}, },
{ {
name: 'KDA', name: 'KDA',
props: 'kda' props: 'kda',
}, },
{ {
name: 'KP', name: 'KP',
props: 'kp' props: 'kp',
}, },
{ {
name: 'Minions', name: 'Minions',
props: 'minions' props: 'minions',
}, },
{ {
name: 'Gold', name: 'Gold',
props: 'gold' props: 'gold',
}, },
{ {
name: 'Dmg <br> champ', name: 'Dmg <br> champ',
props: 'dmgChamp' props: 'dmgChamp',
}, },
{ {
name: 'Dmg <br> taken', name: 'Dmg <br> taken',
props: 'dmgTaken' props: 'dmgTaken',
}, },
{ {
name: 'Game <br> length', name: 'Game <br> length',
props: 'gameLength' props: 'gameLength',
}, },
{ {
name: 'Last <br> played', name: 'Last <br> played',
props: 'date' props: 'date',
} },
], ],
championsFull: [], championsFull: [],
sortProps: 'index', sortProps: 'index',
order: -1 order: -1,
} }
}, },
computed: { computed: {
championsToDisplay() { championsToDisplay() {
return this.championsFull.filter(c => { return this.championsFull.filter((c) => {
const playedEnough = this.onlyMostPlayed ? c.playrate >= 1 : true const playedEnough = this.onlyMostPlayed ? c.playrate >= 1 : true
const searched = c.champion.name.toLowerCase().includes(this.search.toLowerCase()) const searched = c.champion.name.toLowerCase().includes(this.search.toLowerCase())
return playedEnough && searched return playedEnough && searched
@ -227,7 +225,7 @@ export default {
}, },
totalGames() { totalGames() {
return this.champions.reduce((agg, champ) => agg + champ.count, 0) return this.champions.reduce((agg, champ) => agg + champ.count, 0)
} },
}, },
watch: { watch: {
@ -236,7 +234,7 @@ export default {
}, },
championsToDisplay() { championsToDisplay() {
this.reApplySorts() this.reApplySorts()
} },
}, },
created() { created() {
@ -247,15 +245,16 @@ export default {
bgColor(champion, stats) { bgColor(champion, stats) {
const biggestValue = Math.max( const biggestValue = Math.max(
...this.championsToDisplay ...this.championsToDisplay
.filter(c => c[stats] !== Infinity) .filter((c) => c[stats] !== Infinity)
.map(c => parseFloat(c[stats])) .map((c) => parseFloat(c[stats])),
, 0) 0
)
// Take the second biggest Value if it's an Infinity KDA // Take the second biggest Value if it's an Infinity KDA
const value = champion[stats] === Infinity ? biggestValue : parseFloat(champion[stats]) const value = champion[stats] === Infinity ? biggestValue : parseFloat(champion[stats])
const opacity = (value / biggestValue).toFixed(2) const opacity = (value / biggestValue).toFixed(2)
return { return {
backgroundColor: `rgba(${colors[stats]}, ${opacity})` backgroundColor: `rgba(${colors[stats]}, ${opacity})`,
} }
}, },
sortBy(props) { sortBy(props) {
@ -271,8 +270,7 @@ export default {
const bProp = props.split('.').reduce((p, c) => p && p[c], b) const bProp = props.split('.').reduce((p, c) => p && p[c], b)
let order = typeof aProp === 'string' ? aProp.localeCompare(bProp) : aProp - bProp let order = typeof aProp === 'string' ? aProp.localeCompare(bProp) : aProp - bProp
if (this.order == -1) if (this.order == -1) order *= -1
order *= -1
// Revert order for rank and champion name // Revert order for rank and champion name
if (props === 'index' || props === 'champion.name') { if (props === 'index' || props === 'champion.name') {
@ -297,20 +295,22 @@ export default {
}, },
updateChampionsList() { updateChampionsList() {
this.championsFull = this.champions.map((champ, index) => { this.championsFull = this.champions.map((champ, index) => {
let kda = champ.kills === 0 && champ.assists === 0 && champ.deaths === 0 ? 0 : (champ.kills + champ.assists) / champ.deaths let kda =
champ.kills === 0 && champ.assists === 0 && champ.deaths === 0
? 0
: (champ.kills + champ.assists) / champ.deaths
return { return {
...champ, ...champ,
winrate: champ.wins * 100 / champ.count, winrate: (champ.wins * 100) / champ.count,
playrate: champ.count * 100 / this.totalGames, playrate: (champ.count * 100) / this.totalGames,
kda, kda,
index, index,
lastPlayed: timeDifference(champ.date), lastPlayed: timeDifference(champ.date),
show: true show: true,
} }
}) })
} },
} },
} }
</script> </script>
@ -320,7 +320,7 @@ export default {
} }
.border-t-table::after { .border-t-table::after {
content: ""; content: '';
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
@ -330,7 +330,7 @@ export default {
} }
.sorted::after { .sorted::after {
content: ""; content: '';
position: absolute; position: absolute;
top: -15px; top: -15px;
left: 0; left: 0;

View file

@ -3,15 +3,17 @@
<select <select
v-model="queue" v-model="queue"
@change="filterQueue" @change="filterQueue"
class="block w-full px-4 py-2 pr-8 font-semibold capitalize bg-blue-800 rounded-md appearance-none cursor-pointer hover:bg-blue-700 focus:outline-none" class="block w-full cursor-pointer appearance-none rounded-md bg-blue-800 px-4 py-2 pr-8 font-semibold capitalize hover:bg-blue-700 focus:outline-none"
style="width: 144px;" style="width: 144px"
> >
<option v-for="(key) in Object.keys(choices)" :key="key" :value="key">{{ choices[key].name }}</option> <option v-for="key in Object.keys(choices)" :key="key" :value="key">
{{ choices[key].name }}
</option>
</select> </select>
<div <div
class="absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 pointer-events-none" class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
> >
<svg class="w-5 h-5 text-white"> <svg class="h-5 w-5 text-white">
<use xlink:href="#chevron-down" /> <use xlink:href="#chevron-down" />
</svg> </svg>
</div> </div>
@ -25,12 +27,12 @@ export default {
props: { props: {
choices: { choices: {
type: Object, type: Object,
required: true required: true,
} },
}, },
data() { data() {
return { return {
queue: '' queue: '',
} }
}, },
@ -41,8 +43,7 @@ export default {
destroyed() { destroyed() {
// Reload all champions stats for next user visit of the champions tab // Reload all champions stats for next user visit of the champions tab
if (this.queue !== 0) if (this.queue !== 0) this.championsNotLoaded()
this.championsNotLoaded()
}, },
methods: { methods: {
@ -50,6 +51,6 @@ export default {
this.$emit('filter-queue', this.queue) this.$emit('filter-queue', this.queue)
}, },
...mapActions('summoner', ['championsNotLoaded']), ...mapActions('summoner', ['championsNotLoaded']),
} },
} }
</script> </script>

View file

@ -12,7 +12,7 @@
<label for="onlyMostPlayed" class="cursor-pointer select-none">Only most played</label> <label for="onlyMostPlayed" class="cursor-pointer select-none">Only most played</label>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-xs text-center text-white"> <div class="px-2 text-center text-xs text-white">
Hide champions with less than Hide champions with less than
<br /> <br />
<span class="font-bold text-teal-400">1% playrate</span> <span class="font-bold text-teal-400">1% playrate</span>
@ -35,14 +35,14 @@ export default {
props: { props: {
value: { value: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
methods: { methods: {
change(e) { change(e) {
this.$emit('input', e.target.checked) this.$emit('input', e.target.checked)
} },
} },
} }
</script> </script>

View file

@ -1,27 +1,22 @@
<template> <template>
<div class="relative self-end inline-block leading-none text-blue-200 group"> <div class="group relative inline-block self-end leading-none text-blue-200">
<select <select
v-model="season" v-model="season"
@change="filterSeason" @change="filterSeason"
dir="rtl" dir="rtl"
class="block w-full px-4 pr-8 bg-transparent rounded-md appearance-none cursor-pointer focus:outline-none group-hover:text-white" class="block w-full cursor-pointer appearance-none rounded-md bg-transparent px-4 pr-8 focus:outline-none group-hover:text-white"
> >
<option :value="null" class="bg-blue-800">All seasons</option> <option :value="null" class="bg-blue-800">All seasons</option>
<option <option v-for="(s, index) in sortedSeasons" :key="index" :value="s" class="bg-blue-800">
v-for="(s, index) in sortedSeasons"
:key="index"
:value="s"
class="bg-blue-800"
>
<template v-if="Number.isInteger(s)">Season {{ s }}</template> <template v-if="Number.isInteger(s)">Season {{ s }}</template>
<!-- Preseason numbers are stored in this format: 10.5 for Preseason 11 --> <!-- Preseason numbers are stored in this format: 10.5 for Preseason 11 -->
<template v-else>Preseason {{ s + 0.5 }}</template> <template v-else>Preseason {{ s + 0.5 }}</template>
</option> </option>
</select> </select>
<div <div
class="absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 pointer-events-none" class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
> >
<svg class="w-4 h-4 text-blue-200 group-hover:text-white"> <svg class="h-4 w-4 text-blue-200 group-hover:text-white">
<use xlink:href="#caret-down" /> <use xlink:href="#caret-down" />
</svg> </svg>
</div> </div>
@ -34,7 +29,7 @@ import { mapActions, mapState } from 'vuex'
export default { export default {
data() { data() {
return { return {
season: null season: null,
} }
}, },
@ -43,8 +38,8 @@ export default {
return [...this.seasons].sort((a, b) => b - a) return [...this.seasons].sort((a, b) => b - a)
}, },
...mapState({ ...mapState({
currentseason: state => state.summoner.basic.currentSeason, currentseason: (state) => state.summoner.basic.currentSeason,
seasons: state => state.summoner.basic.seasons, seasons: (state) => state.summoner.basic.seasons,
}), }),
}, },
@ -56,7 +51,7 @@ export default {
filterSeason() { filterSeason() {
this.updateSeason(this.season) this.updateSeason(this.season)
}, },
...mapActions('summoner', ['updateSeason']) ...mapActions('summoner', ['updateSeason']),
} },
} }
</script> </script>

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="pb-2 text-white"> <div class="pb-2 text-white">
<div class="flex justify-between"> <div class="flex justify-between">
<div style="width: 520px; height: 239px;"> <div style="width: 520px; height: 239px">
<content-loader <content-loader
:height="239" :height="239"
:width="520" :width="520"
@ -23,7 +23,7 @@
</content-loader> </content-loader>
</div> </div>
<div class="rounded-lg bg-blue-850" style="width: 347px; height: 215px;"> <div class="rounded-lg bg-blue-850" style="width: 347px; height: 215px">
<content-loader <content-loader
:height="215" :height="215"
:width="347" :width="347"
@ -157,7 +157,7 @@ import { ContentLoader } from 'vue-content-loader'
export default { export default {
components: { components: {
ContentLoader ContentLoader,
} },
} }
</script> </script>

View file

@ -1,18 +1,17 @@
<template> <template>
<div class="px-5 py-4 mt-2 bg-blue-800 rounded-lg"> <div class="mt-2 rounded-lg bg-blue-800 px-5 py-4">
<table <table
class="w-full leading-none text-center table-fixed" class="w-full table-fixed text-center leading-none"
style="border-collapse:separate; border-spacing:0 0.5rem;" style="border-collapse: separate; border-spacing: 0 0.5rem"
> >
<thead> <thead>
<tr class="text-left"> <tr class="text-left">
<th <th :class="[ally ? 'text-teal-400 ' : 'text-red-400 ']" class="w-team font-semibold">
:class="[ally ? 'text-teal-400 ' : 'text-red-400 ']" {{ ally ? 'Ally' : 'Enemy' }} Team
class="font-semibold w-team" </th>
>{{ ally ? 'Ally' : 'Enemy' }} Team</th> <th class="w-ranked text-sm font-normal text-blue-200">SoloQ Stats</th>
<th class="text-sm font-normal text-blue-200 w-ranked">SoloQ Stats</th> <th class="w-ranked text-sm font-normal text-blue-200">Flex Stats</th>
<th class="text-sm font-normal text-blue-200 w-ranked">Flex Stats</th> <th class="w-bans px-2 text-right text-sm font-normal text-blue-200">Bans</th>
<th class="px-2 text-sm font-normal text-right text-blue-200 w-bans">Bans</th>
</tr> </tr>
</thead> </thead>
<tbody v-if="liveLoaded"> <tbody v-if="liveLoaded">
@ -20,64 +19,70 @@
v-for="(player, index) in team" v-for="(player, index) in team"
:key="player.summonerId" :key="player.summonerId"
:style="getCSSVars(player.championId)" :style="getCSSVars(player.championId)"
class="relative live-team-row" class="live-team-row relative"
> >
<td class="py-1 pl-2 rounded-l-lg"> <td class="rounded-l-lg py-1 pl-2">
<div class="flex items-center"> <div class="flex items-center">
<div <div
v-if="player.perks" v-if="player.perks"
@click="selectRunes(player)" @click="selectRunes(player)"
:class="{ 'cursor-pointer': player.perks }" :class="{ 'cursor-pointer': player.perks }"
class="flex flex-col items-center runes" class="runes flex flex-col items-center"
> >
<div <div
:style="{backgroundImage: `url('${getPrimarRune(player.perks)}')`}" :style="{ backgroundImage: `url('${getPrimarRune(player.perks)}')` }"
class="w-6 h-6 bg-center bg-cover" class="h-6 w-6 bg-cover bg-center"
></div> ></div>
<div <div
:style="{backgroundImage: `url('${getSecondaryRune(player.perks)}')`}" :style="{ backgroundImage: `url('${getSecondaryRune(player.perks)}')` }"
class="w-3 h-3 mt-1 bg-center bg-cover" class="mt-1 h-3 w-3 bg-cover bg-center"
></div> ></div>
</div> </div>
<div v-else class="w-6"></div> <div v-else class="w-6"></div>
<div <div
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${player.championId}.png')`}" :style="{
backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${player.championId}.png')`,
}"
:class="borderChampion(player.summonerId)" :class="borderChampion(player.summonerId)"
class="relative w-12 h-12 ml-2 bg-center bg-cover border-2 rounded-full bg-blue-1000" class="relative ml-2 h-12 w-12 rounded-full border-2 bg-blue-1000 bg-cover bg-center"
> >
<div <div
v-if="player.role && player.role !== 'NONE'" v-if="player.role && player.role !== 'NONE'"
:class="borderChampion(player.summonerId)" :class="borderChampion(player.summonerId)"
class="absolute border rounded-full p-2px bg-blue-1000" class="absolute rounded-full border bg-blue-1000 p-0.5"
style="bottom: -5px; right: -5px;" style="bottom: -5px; right: -5px"
> >
<div <div
:style="{backgroundImage: `url(${require('@/assets/img/roles/' + player.role + '.png')})`}" :style="{ backgroundImage: `url(${'/img/roles/' + player.role + '.png'})` }"
class="w-4 h-4 bg-center bg-cover" class="h-4 w-4 bg-cover bg-center"
></div> ></div>
</div> </div>
</div> </div>
<div class="flex flex-col ml-2"> <div class="ml-2 flex flex-col">
<div <div
:style="{backgroundImage: `url(${player.summonerSpell1.icon})`}" :style="{ backgroundImage: `url(${player.summonerSpell1.icon})` }"
class="w-4 h-4 bg-center bg-cover rounded-md bg-blue-1000" class="h-4 w-4 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div <div
:style="{backgroundImage: `url(${player.summonerSpell2.icon})`}" :style="{ backgroundImage: `url(${player.summonerSpell2.icon})` }"
class="w-4 h-4 mt-1 bg-center bg-cover rounded-md bg-blue-1000" class="mt-1 h-4 w-4 rounded-md bg-blue-1000 bg-cover bg-center"
></div> ></div>
</div> </div>
<div class="ml-3 text-sm leading-tight text-left"> <div class="ml-3 text-left text-sm leading-tight">
<router-link <router-link
v-if="!player.bot" v-if="!player.bot"
:to="{ name: 'summoner', params: { region: $route.params.region, name: player.summonerName }}" :to="{
:class="[player.summonerId === account.id ? 'text-yellow-500' : 'hover:text-blue-200']" name: 'summoner',
params: { region: $route.params.region, name: player.summonerName },
}"
:class="[
player.summonerId === account.id ? 'text-yellow-500' : 'hover:text-blue-200',
]"
class="font-semibold" class="font-semibold"
>{{ player.summonerName }}</router-link> >{{ player.summonerName }}</router-link
<div >
:class="[ally ? 'text-teal-300 ' : 'text-red-400 ']" <div :class="[ally ? 'text-teal-300 ' : 'text-red-400 ']" class="text-xs">
class="text-xs" {{ player.champion.name }}
>{{ player.champion.name }}
</div> </div>
</div> </div>
</div> </div>
@ -86,21 +91,21 @@
<div class="px-2"> <div class="px-2">
<div v-if="player.rank.soloQ" class="flex items-center"> <div v-if="player.rank.soloQ" class="flex items-center">
<div class="inline-block text-center"> <div class="inline-block text-center">
<svg class="w-5 h-5"> <svg class="h-5 w-5">
<use :xlink:href="`#rank-${player.rank.soloQ.tier.toLowerCase()}`" /> <use :xlink:href="`#rank-${player.rank.soloQ.tier.toLowerCase()}`" />
</svg> </svg>
<div <div class="mt-0.5 text-xs font-semibold text-blue-300">
class="text-xs font-semibold text-blue-300 mt-2px" {{ player.rank.soloQ.shortName }}
>{{ player.rank.soloQ.shortName }}</div> </div>
</div> </div>
<div class="ml-5 text-center"> <div class="ml-5 text-center">
<div class="font-semibold">{{ player.rank.soloQ.winrate }}</div> <div class="font-semibold">{{ player.rank.soloQ.winrate }}</div>
<div <div class="mt-1 text-xs text-blue-300">
class="mt-1 text-xs text-blue-300" {{ player.rank.soloQ.wins + player.rank.soloQ.losses }} games
>{{ player.rank.soloQ.wins + player.rank.soloQ.losses }} games</div> </div>
</div> </div>
</div> </div>
<div v-else class="w-5 h-5"> <div v-else class="h-5 w-5">
<div class="-mt-1 text-2xl text-blue-300">-</div> <div class="-mt-1 text-2xl text-blue-300">-</div>
</div> </div>
</div> </div>
@ -109,46 +114,52 @@
<div class="px-2"> <div class="px-2">
<div v-if="player.rank.flex5v5" class="flex items-center"> <div v-if="player.rank.flex5v5" class="flex items-center">
<div class="inline-block text-center"> <div class="inline-block text-center">
<svg class="w-5 h-5"> <svg class="h-5 w-5">
<use :xlink:href="`#rank-${player.rank.flex5v5.tier.toLowerCase()}`" /> <use :xlink:href="`#rank-${player.rank.flex5v5.tier.toLowerCase()}`" />
</svg> </svg>
<div <div class="mt-0.5 text-xs font-semibold text-blue-300">
class="text-xs font-semibold text-blue-300 mt-2px" {{ player.rank.flex5v5.shortName }}
>{{ player.rank.flex5v5.shortName }}</div> </div>
</div> </div>
<div class="ml-5 text-center"> <div class="ml-5 text-center">
<div class="font-semibold">{{ player.rank.flex5v5.winrate }}</div> <div class="font-semibold">{{ player.rank.flex5v5.winrate }}</div>
<div <div class="mt-1 text-xs text-blue-300">
class="mt-1 text-xs text-blue-300" {{ player.rank.flex5v5.wins + player.rank.flex5v5.losses }} games
>{{ player.rank.flex5v5.wins + player.rank.flex5v5.losses }} games</div> </div>
</div> </div>
</div> </div>
<div v-else class="w-5 h-5"> <div v-else class="h-5 w-5">
<div class="-mt-1 text-2xl text-blue-300">-</div> <div class="-mt-1 text-2xl text-blue-300">-</div>
</div> </div>
</div> </div>
</td> </td>
<td class="py-1 text-right rounded-r-lg"> <td class="rounded-r-lg py-1 text-right">
<div class="inline-block px-2"> <div class="inline-block px-2">
<div <div
v-if="live.bannedChampions.length" v-if="live.bannedChampions.length"
:class="[ally ? 'ban-blue border-teal-500' : 'ban-red border-red-500']" :class="[ally ? 'ban-blue border-teal-500' : 'ban-red border-red-500']"
class="relative border-2 rounded-full ban" class="ban relative rounded-full border-2"
> >
<div <div
:style="[ :style="[
banChamp(index, player.teamId) ? banChamp(index, player.teamId)
{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${banChamp(index, player.teamId).championId}.png')`} ? {
: '' backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${
banChamp(index, player.teamId).championId
}.png')`,
}
: '',
]" ]"
class="w-6 h-6 bg-center bg-cover rounded-full ban-img bg-blue-1000" class="ban-img h-6 w-6 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div <div
:class="[ally ? 'text-teal-100 bg-teal-500' : 'text-red-100 bg-red-500']" :class="[ally ? 'bg-teal-500 text-teal-100' : 'bg-red-500 text-red-100']"
class="absolute flex items-center justify-center w-4 h-4 text-xs font-bold rounded-full ban-order" class="ban-order absolute flex h-4 w-4 items-center justify-center rounded-full text-xs font-bold"
>{{ banChamp(index, player.teamId).pickTurn }}</div> >
{{ banChamp(index, player.teamId).pickTurn }}
</div>
</div> </div>
<div v-else class="w-5 h-5 text-left"> <div v-else class="h-5 w-5 text-left">
<div class="text-2xl text-blue-300">-</div> <div class="text-2xl text-blue-300">-</div>
</div> </div>
</div> </div>
@ -202,7 +213,7 @@ export default {
props: { props: {
team: { team: {
type: Array, type: Array,
required: true required: true,
}, },
ally: { ally: {
type: Boolean, type: Boolean,
@ -211,19 +222,19 @@ export default {
gamemode: { gamemode: {
type: String, type: String,
default: '', default: '',
} },
}, },
data() { data() {
return { return {
clashGameBanOrder: { clashGameBanOrder: {
100: [1, 3, 5, 8, 10], 100: [1, 3, 5, 8, 10],
200: [2, 4, 6, 7, 9] 200: [2, 4, 6, 7, 9],
}, },
customGameBanOrder: { customGameBanOrder: {
100: [1, 3, 5, 2, 4], 100: [1, 3, 5, 2, 4],
200: [2, 4, 6, 1, 3] 200: [2, 4, 6, 1, 3],
} },
} }
}, },
@ -235,10 +246,10 @@ export default {
return this.gamemode === 'Custom Game' return this.gamemode === 'Custom Game'
}, },
...mapState({ ...mapState({
account: state => state.summoner.basic.account, account: (state) => state.summoner.basic.account,
live: state => state.summoner.live.match, live: (state) => state.summoner.live.match,
liveLoaded: state => state.summoner.live.liveLoaded, liveLoaded: (state) => state.summoner.live.liveLoaded,
}) }),
}, },
methods: { methods: {
@ -254,7 +265,7 @@ export default {
toFind = this.customGameBanOrder[teamId][index] toFind = this.customGameBanOrder[teamId][index]
} }
return this.live.bannedChampions.find(b => b.pickTurn === toFind && b.teamId === teamId) return this.live.bannedChampions.find((b) => b.pickTurn === toFind && b.teamId === teamId)
}, },
borderChampion(id) { borderChampion(id) {
if (id === this.account.id) { if (id === this.account.id) {
@ -270,14 +281,13 @@ export default {
} }
}, },
selectRunes(player) { selectRunes(player) {
if(!player.perks) if (!player.perks) return
return this.displayRunes(player.perks)
this.displayOrHideRunes(player.perks)
}, },
getPrimarRune, getPrimarRune,
getSecondaryRune, getSecondaryRune,
...mapActions('cdragon', ['displayOrHideRunes']), ...mapActions('cdragon', ['displayRunes']),
} },
} }
</script> </script>
@ -299,7 +309,7 @@ export default {
} }
.live-team-row td:first-child:before { .live-team-row td:first-child:before {
content: ""; content: '';
position: absolute; position: absolute;
z-index: -10; z-index: -10;
top: 0; top: 0;

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="flex mt-3 text-center"> <div class="mt-3 flex text-center">
<div class="w-3/12"> <div class="w-3/12">
<div class="rounded-lg bg-blue-850" style="width: 300px; height: 339px;"> <div class="rounded-lg bg-blue-850" style="width: 300px; height: 339px">
<content-loader <content-loader
:height="339" :height="339"
:width="300" :width="300"
@ -41,7 +41,7 @@
<rect x="246" y="308" rx="3" ry="3" width="42" height="16" /> <rect x="246" y="308" rx="3" ry="3" width="42" height="16" />
</content-loader> </content-loader>
</div> </div>
<div class="mt-4 rounded-lg bg-blue-850" style="width: 300px; height: 828px;"> <div class="mt-4 rounded-lg bg-blue-850" style="width: 300px; height: 828px">
<content-loader <content-loader
:height="828" :height="828"
:width="300" :width="300"
@ -133,7 +133,7 @@
</content-loader> </content-loader>
</div> </div>
<div class="mt-4 rounded-lg bg-blue-850" style="width: 300px; height: 384px;"> <div class="mt-4 rounded-lg bg-blue-850" style="width: 300px; height: 384px">
<content-loader <content-loader
:height="384" :height="384"
:width="300" :width="300"
@ -191,9 +191,9 @@
<div <div
v-for="index in 10" v-for="index in 10"
:key="index" :key="index"
:class="{'mt-4': index !== 1}" :class="{ 'mt-4': index !== 1 }"
class="ml-4 rounded-lg bg-blue-850" class="ml-4 rounded-lg bg-blue-850"
style="width: 884px; height: 144px;" style="width: 884px; height: 144px"
> >
<content-loader <content-loader
:height="144" :height="144"
@ -242,7 +242,7 @@
<rect x="803" y="90" rx="3" ry="3" width="59" height="14" /> <rect x="803" y="90" rx="3" ry="3" width="59" height="14" />
</content-loader> </content-loader>
</div> </div>
<div class="mx-auto mt-4" style="width: 135px; height: 40px;"> <div class="mx-auto mt-4" style="width: 135px; height: 40px">
<content-loader <content-loader
:height="40" :height="40"
:width="135" :width="135"
@ -262,7 +262,7 @@ import { ContentLoader } from 'vue-content-loader'
export default { export default {
components: { components: {
ContentLoader ContentLoader,
} },
} }
</script> </script>

View file

@ -1,27 +1,30 @@
<template> <template>
<div class="bg-blue-800 rounded-lg"> <div class="rounded-lg bg-blue-800">
<div class="relative flex items-center justify-center py-4 text-blue-200 rounded-t-lg heading"> <div class="heading relative flex items-center justify-center rounded-t-lg py-4 text-blue-200">
<svg class="w-5 h-5" style="transform: rotate(-5deg);"> <svg class="h-5 w-5" style="transform: rotate(-5deg)">
<use xlink:href="#layers" /> <use xlink:href="#layers" />
</svg> </svg>
<span class="mx-4 text-lg font-semibold uppercase">CHAMPIONS</span> <span class="mx-4 text-lg font-semibold uppercase">CHAMPIONS</span>
<svg class="w-5 h-5" style="transform: rotate(5deg);"> <svg class="h-5 w-5" style="transform: rotate(5deg)">
<use xlink:href="#layers" /> <use xlink:href="#layers" />
</svg> </svg>
<div class="absolute top-0 right-0 mt-3 mr-2"> <div class="absolute right-0 top-0 mr-2 mt-3">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<svg class="w-4 h-4 cursor-pointer"> <svg class="h-4 w-4 cursor-pointer">
<use xlink:href="#info" /> <use xlink:href="#info" />
</svg> </svg>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-sm text-center text-white select-none"> <div class="select-none px-2 text-center text-sm text-white">
<div>Stats based on</div> <div>Stats based on</div>
<div> <div>
<span class="font-bold text-teal-400">{{ stats.global ? stats.global.count : 0 }}</span> matches <span class="font-bold text-teal-400">{{
stats.global ? stats.global.count : 0
}}</span>
matches
</div> </div>
<div class="mt-2 text-xs italic font-normal leading-tight text-blue-100"> <div class="mt-2 text-xs font-normal italic leading-tight text-blue-100">
Load more matches Load more matches
<br />to have better results. <br />to have better results.
</div> </div>
@ -31,48 +34,57 @@
</div> </div>
</div> </div>
<div v-if="stats.champion.length"> <div v-if="stats.champion.length">
<div class="flex items-baseline px-4 mt-3 text-xs font-semibold text-left text-blue-300 uppercase"> <div
<div class="ml-2 text-base text-blue-400 w-champion">Champion</div> class="mt-3 flex items-baseline px-4 text-left text-xs font-semibold uppercase text-blue-300"
>
<div class="w-champion ml-2 text-base text-blue-400">Champion</div>
<div class="w-plays">Plays</div> <div class="w-plays">Plays</div>
<div class="w-winrate">Winrate</div> <div class="w-winrate">Winrate</div>
<div class="w-kda">KDA</div> <div class="w-kda">KDA</div>
</div> </div>
<ul class="mt-1 text-sm text-left text-gray-100"> <ul class="mt-1 text-left text-sm text-gray-100">
<li <li
v-for="(champion, index) in stats.champion" v-for="(champion, index) in stats.champion"
:key="index" :key="index"
:class="[{'rounded-b-lg': index === stats.champion.length - 1}, {'bg-blue-760': index % 2 === 0}]" :class="[
{ 'rounded-b-lg': index === stats.champion.length - 1 },
{ 'bg-blue-760': index % 2 === 0 },
]"
class="relative flex items-center px-4 py-2 leading-tight" class="relative flex items-center px-4 py-2 leading-tight"
> >
<div class="absolute text-xs" style="left: 6px;">{{ index + 1 }}.</div> <div class="absolute text-xs" style="left: 6px">{{ index + 1 }}.</div>
<div class="flex items-center ml-2 w-champion"> <div class="w-champion ml-2 flex items-center">
<div <div
:style="{backgroundImage: `url('${champion.champion.icon}')`}" :style="{ backgroundImage: `url('${champion.champion.icon}')` }"
class="flex-shrink-0 w-8 h-8 bg-center bg-cover rounded-full bg-blue-1000" class="h-8 w-8 flex-shrink-0 rounded-full bg-blue-1000 bg-cover bg-center"
></div> ></div>
<div class="mx-1 truncate">{{ champion.champion.name }}</div> <div class="mx-1 truncate">{{ champion.champion.name }}</div>
</div> </div>
<div class="w-plays"> <div class="w-plays">
<div class="text-xs text-purple-400">{{ champion.count }}</div> <div class="text-xs text-purple-400">{{ champion.count }}</div>
<div <div
:style="{width: widthBar(champion.count, mostPlayed)}" :style="{ width: widthBar(champion.count, mostPlayed) }"
class="h-1 bg-purple-400 rounded-full mt-2px" class="mt-0.5 h-1 rounded-full bg-purple-400"
></div> ></div>
</div> </div>
<div class="w-winrate"> <div class="w-winrate">
<div class="text-xs text-green-400">{{ champion.wins * 100 / champion.count|percent }}</div> <div class="text-xs text-green-400">
{{ ((champion.wins * 100) / champion.count) | percent }}
</div>
<div <div
:style="{width: widthBar(champion.wins, champion.count)}" :style="{ width: widthBar(champion.wins, champion.count) }"
class="h-1 bg-green-400 rounded-full mt-2px" class="mt-0.5 h-1 rounded-full bg-green-400"
></div> ></div>
</div> </div>
<div class="w-kda"> <div class="w-kda">
<div class="text-xs text-blue-400">
{{ kda(champion.kills, champion.deaths, champion.assists) }}
</div>
<div <div
class="text-xs text-blue-400" :style="{
>{{ kda(champion.kills, champion.deaths, champion.assists) }}</div> width: widthBar(kda(champion.kills, champion.deaths, champion.assists), bestKda),
<div }"
:style="{width: widthBar(kda(champion.kills, champion.deaths, champion.assists), bestKda)}" class="mt-0.5 h-1 rounded-full bg-blue-400"
class="h-1 bg-blue-400 rounded-full mt-2px"
></div> ></div>
</div> </div>
</li> </li>
@ -97,15 +109,17 @@ export default {
computed: { computed: {
bestKda() { bestKda() {
const bestChamp = this.stats.champion.reduce((a, b) => { const bestChamp = this.stats.champion.reduce((a, b) => {
return this.kda(a.kills, a.deaths, a.assists) > this.kda(b.kills, b.deaths, b.assists) ? a : b return this.kda(a.kills, a.deaths, a.assists) > this.kda(b.kills, b.deaths, b.assists)
? a
: b
}) })
return this.kda(bestChamp.kills, bestChamp.deaths, bestChamp.assists) return this.kda(bestChamp.kills, bestChamp.deaths, bestChamp.assists)
}, },
mostPlayed() { mostPlayed() {
return this.stats.champion.reduce((a, b) => a.count > b.count ? a : b).count return this.stats.champion.reduce((a, b) => (a.count > b.count ? a : b)).count
}, },
...mapState({ ...mapState({
stats: state => state.summoner.overview.stats stats: (state) => state.summoner.overview.stats,
}), }),
}, },
@ -117,9 +131,9 @@ export default {
return this.$options.filters.round((kills + assists) / deaths) return this.$options.filters.round((kills + assists) / deaths)
}, },
widthBar(value, total) { widthBar(value, total) {
return `${value * 36 / total}px` return `${(value * 36) / total}px`
} },
} },
} }
</script> </script>

View file

@ -1,17 +1,17 @@
<template> <template>
<div class="mt-4 bg-blue-800 rounded-lg"> <div class="mt-4 rounded-lg bg-blue-800">
<div class="pb-2"> <div class="pb-2">
<div class="flex items-center justify-center py-4 text-blue-200 rounded-t-lg heading"> <div class="heading flex items-center justify-center rounded-t-lg py-4 text-blue-200">
<svg class="w-5 h-5" style="transform: rotate(-5deg);"> <svg class="h-5 w-5" style="transform: rotate(-5deg)">
<use xlink:href="#people" /> <use xlink:href="#people" />
</svg> </svg>
<span class="mx-4 text-lg font-semibold uppercase">FRIENDS</span> <span class="mx-4 text-lg font-semibold uppercase">FRIENDS</span>
<svg class="w-5 h-5" style="transform: rotate(5deg);"> <svg class="h-5 w-5" style="transform: rotate(5deg)">
<use xlink:href="#people" /> <use xlink:href="#people" />
</svg> </svg>
</div> </div>
<div v-if="hasMates" class="px-4 py-2 text-sm text-left"> <div v-if="hasMates" class="px-4 py-2 text-left text-sm">
<div class="flex items-baseline text-xs font-semibold text-blue-300 uppercase"> <div class="flex items-baseline text-xs font-semibold uppercase text-blue-300">
<div class="w-2/4 text-base text-blue-400">Summoner</div> <div class="w-2/4 text-base text-blue-400">Summoner</div>
<div class="w-1/4">Record</div> <div class="w-1/4">Record</div>
<div class="w-1/4">Winrate</div> <div class="w-1/4">Winrate</div>
@ -23,29 +23,31 @@
class="flex items-center justify-between" class="flex items-center justify-between"
> >
<router-link <router-link
:to="{ name: 'summoner', params: { region: $route.params.region, name: mate.name }}" :to="{ name: 'summoner', params: { region: $route.params.region, name: mate.name } }"
class="w-2/4 truncate hover:text-teal-200" class="w-2/4 truncate hover:text-teal-200"
>{{ mate.name }}</router-link> >{{ mate.name }}</router-link
>
<div class="w-1/4">{{ mate.wins }} / {{ mate.losses }}</div> <div class="w-1/4">{{ mate.wins }} / {{ mate.losses }}</div>
<div class="w-1/4"> <div class="w-1/4">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<div class="h-2 bg-blue-900 rounded-full cursor-pointer"> <div class="h-2 cursor-pointer rounded-full bg-blue-900">
<div <div
:class="getWinrateColor(mate.wins, mate.count)" :class="getWinrateColor(mate.wins, mate.count)"
:style="{width: `${winrate(mate.wins, mate.count)}%`}" :style="{ width: `${winrate(mate.wins, mate.count)}%` }"
class="h-full rounded-full" class="h-full rounded-full"
></div> ></div>
</div> </div>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-xs text-center text-white"> <div class="px-2 text-center text-xs text-white">
<div>Winrate</div> <div>Winrate</div>
<div> <div>
<span <span
:class="getWinrateColor(mate.wins, mate.count, false)" :class="getWinrateColor(mate.wins, mate.count, false)"
class="font-bold" class="font-bold"
>{{ winrate(mate.wins, mate.count)|percent }}</span> >{{ winrate(mate.wins, mate.count) | percent }}</span
>
</div> </div>
</div> </div>
</template> </template>
@ -73,7 +75,7 @@ export default {
data() { data() {
return { return {
maxMates: 15 maxMates: 15,
} }
}, },
@ -82,7 +84,7 @@ export default {
return this.mates.length > 0 return this.mates.length > 0
}, },
...mapState({ ...mapState({
mates: state => state.summoner.overview.stats.mates mates: (state) => state.summoner.overview.stats.mates,
}), }),
}, },
@ -99,8 +101,8 @@ export default {
return background ? 'bg-teal-200' : 'text-teal-200' return background ? 'bg-teal-200' : 'text-teal-200'
}, },
winrate(wins, count) { winrate(wins, count) {
return wins * 100 / count return (wins * 100) / count
} },
} },
} }
</script> </script>

View file

@ -1,27 +1,27 @@
<template> <template>
<div v-if="stats.global" class="mt-4 bg-blue-800 rounded-lg"> <div v-if="stats.global" class="mt-4 rounded-lg bg-blue-800">
<div class="relative flex justify-center py-4 text-blue-200 rounded-t-lg heading"> <div class="heading relative flex justify-center rounded-t-lg py-4 text-blue-200">
<svg class="w-6 h-6"> <svg class="h-6 w-6">
<use xlink:href="#graph" /> <use xlink:href="#graph" />
</svg> </svg>
<span class="mx-4 text-lg font-semibold uppercase">STATS</span> <span class="mx-4 text-lg font-semibold uppercase">STATS</span>
<svg class="w-6 h-6" style="transform: scaleX(-1);"> <svg class="h-6 w-6" style="transform: scaleX(-1)">
<use xlink:href="#graph" /> <use xlink:href="#graph" />
</svg> </svg>
<div class="absolute top-0 right-0 mt-3 mr-2"> <div class="absolute right-0 top-0 mr-2 mt-3">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<svg class="w-4 h-4 cursor-pointer"> <svg class="h-4 w-4 cursor-pointer">
<use xlink:href="#info" /> <use xlink:href="#info" />
</svg> </svg>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-sm text-center text-white select-none"> <div class="select-none px-2 text-center text-sm text-white">
<div>Stats based on</div> <div>Stats based on</div>
<div> <div>
<span class="font-bold text-teal-400">{{ stats.global.count }}</span> matches <span class="font-bold text-teal-400">{{ stats.global.count }}</span> matches
</div> </div>
<div class="mt-2 text-xs italic font-normal leading-tight text-blue-100"> <div class="mt-2 text-xs font-normal italic leading-tight text-blue-100">
Load more matches Load more matches
<br />to have better results. <br />to have better results.
</div> </div>
@ -30,56 +30,57 @@
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
<div class="flex items-center py-2 mt-2"> <div class="mt-2 flex items-center py-2">
<div <div
v-for="(role, index) in stats.role" v-for="(role, index) in stats.role"
:key="index" :key="index"
class="flex flex-col items-center w-1/5" class="flex w-1/5 flex-col items-center"
> >
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<div class="flex flex-col justify-end w-2 h-12 bg-blue-900 rounded-full cursor-pointer"> <div class="flex h-12 w-2 cursor-pointer flex-col justify-end rounded-full bg-blue-900">
<div <div
:style="{height: (role.count * 3 / mostPlayedRole) * role.wins / role.count + 'rem'}" :style="{
height: (((role.count * 3) / mostPlayedRole) * role.wins) / role.count + 'rem',
}"
:class="roundedRoleWins(role.wins, role.count)" :class="roundedRoleWins(role.wins, role.count)"
class="bg-green-400" class="bg-green-400"
></div> ></div>
<div <div
:style="{height: (role.count * 3 / mostPlayedRole) * role.losses / role.count + 'rem'}" :style="{
height: (((role.count * 3) / mostPlayedRole) * role.losses) / role.count + 'rem',
}"
:class="roundedRoleLosses(role.losses, role.count)" :class="roundedRoleLosses(role.losses, role.count)"
class="bg-red-400" class="bg-red-400"
></div> ></div>
</div> </div>
</template> </template>
<template #default> <template #default>
<div class="px-2 text-sm text-center text-white select-none"> <div class="select-none px-2 text-center text-sm text-white">
<div>{{ role.role|capitalize }}</div> <div>{{ role.role | capitalize }}</div>
<span <span :class="winLossColor(role.wins, role.losses).win" class="font-bold">{{
:class="winLossColor(role.wins, role.losses).win" role.wins
class="font-bold" }}</span>
>{{ role.wins }}</span>
<span class="mx-1 font-bold text-gray-400">-</span> <span class="mx-1 font-bold text-gray-400">-</span>
<span <span :class="winLossColor(role.wins, role.losses).loss" class="font-bold">{{
:class="winLossColor(role.wins, role.losses).loss" role.losses
class="font-bold" }}</span>
>{{ role.losses }}</span> <div :class="calculateWinrate(role.wins, role.count).color" class="mt-1 font-bold">
<div {{ calculateWinrate(role.wins, role.count).winrate | round }}%
:class="calculateWinrate(role.wins, role.count).color" </div>
class="mt-1 font-bold"
>{{ calculateWinrate(role.wins, role.count).winrate|round }}%</div>
</div> </div>
</template> </template>
</Tooltip> </Tooltip>
<div <div
:style="{backgroundImage: `url(${require('@/assets/img/roles/' + role.role + '.png')})`}" :style="{ backgroundImage: `url(${'/img/roles/' + role.role + '.png'})` }"
class="w-4 h-4 mt-1 bg-center bg-cover" class="mt-1 h-4 w-4 bg-cover bg-center"
></div> ></div>
<div class="text-xs text-blue-200">{{ role.count }}</div> <div class="text-xs text-blue-200">{{ role.count }}</div>
</div> </div>
</div> </div>
<div class="py-2 text-sm text-center"> <div class="py-2 text-center text-sm">
<div class="flex items-baseline px-4 text-xs font-semibold text-blue-300 uppercase"> <div class="flex items-baseline px-4 text-xs font-semibold uppercase text-blue-300">
<div class="w-1/4 text-base text-left text-blue-400">Stat</div> <div class="w-1/4 text-left text-base text-blue-400">Stat</div>
<div class="w-1/4">Total</div> <div class="w-1/4">Total</div>
<div class="w-1/4">Per min</div> <div class="w-1/4">Per min</div>
<div class="w-1/4">Avg</div> <div class="w-1/4">Avg</div>
@ -88,34 +89,34 @@
<li <li
v-for="(stat, name, index) in globalStatsKeys" v-for="(stat, name, index) in globalStatsKeys"
:key="index" :key="index"
:class="{'bg-blue-760': index % 2 !== 0}" :class="{ 'bg-blue-760': index % 2 !== 0 }"
class="flex items-center justify-between px-4 py-1 leading-tight" class="flex items-center justify-between px-4 py-1 leading-tight"
> >
<div class="w-1/4 text-left capitalize">{{ name }}</div> <div class="w-1/4 text-left capitalize">{{ name }}</div>
<div class="w-1/4">{{ stat|kilo(false) }}</div> <div class="w-1/4">{{ stat | kilo(false) }}</div>
<div class="w-1/4">{{ stat / (stats.global.time / 60)|round }}</div> <div class="w-1/4">{{ (stat / (stats.global.time / 60)) | round }}</div>
<div class="w-1/4">{{ stat / stats.global.count|round }}</div> <div class="w-1/4">{{ (stat / stats.global.count) | round }}</div>
</li> </li>
<li class="flex items-center justify-between px-4 py-1 leading-tight bg-blue-760"> <li class="flex items-center justify-between bg-blue-760 px-4 py-1 leading-tight">
<div class="w-1/4 text-left whitespace-no-wrap">Time</div> <div class="w-1/4 whitespace-nowrap text-left">Time</div>
<div class="w-1/4">{{ stats.global.time|secToHours }}</div> <div class="w-1/4">{{ stats.global.time | secToHours }}</div>
<div class="w-1/4"></div> <div class="w-1/4"></div>
<div class="w-1/4">{{ (stats.global.time / stats.global.count)|secToTime(true) }}</div> <div class="w-1/4">{{ (stats.global.time / stats.global.count) | secToTime(true) }}</div>
</li> </li>
<li class="flex items-center justify-between px-4 py-1 leading-tight"> <li class="flex items-center justify-between px-4 py-1 leading-tight">
<div class="w-1/4 text-left whitespace-no-wrap">KDA</div> <div class="w-1/4 whitespace-nowrap text-left">KDA</div>
<div <div class="w-1/4">
class="w-1/4" {{ ((stats.global.kills + stats.global.assists) / stats.global.deaths) | round }}
>{{ (stats.global.kills + stats.global.assists) / stats.global.deaths|round }}</div> </div>
</li> </li>
<li class="flex items-center justify-between px-4 py-1 leading-tight bg-blue-760"> <li class="flex items-center justify-between bg-blue-760 px-4 py-1 leading-tight">
<div class="w-1/4 text-left whitespace-no-wrap">Kill participation</div> <div class="w-1/4 whitespace-nowrap text-left">Kill participation</div>
<div class="w-1/4">{{ stats.global.kp|percent }}</div> <div class="w-1/4">{{ stats.global.kp | percent }}</div>
</li> </li>
</ul> </ul>
<template v-if="leagueStatsByType('Ranked').length"> <template v-if="leagueStatsByType('Ranked').length">
<div class="flex items-baseline px-4 mt-3 text-xs font-semibold text-blue-300 uppercase"> <div class="mt-3 flex items-baseline px-4 text-xs font-semibold uppercase text-blue-300">
<div class="w-5/12 text-base text-left text-blue-400">Ranked</div> <div class="w-5/12 text-left text-base text-blue-400">Ranked</div>
<div class="w-3/12">Winrate</div> <div class="w-3/12">Winrate</div>
<div class="w-4/12">Record</div> <div class="w-4/12">Record</div>
</div> </div>
@ -123,31 +124,28 @@
<li <li
v-for="(league, index) in leagueStatsByType('Ranked')" v-for="(league, index) in leagueStatsByType('Ranked')"
:key="index" :key="index"
:class="{'bg-blue-760': index % 2 !== 0}" :class="{ 'bg-blue-760': index % 2 !== 0 }"
class="flex items-center justify-between px-4 py-1 leading-tight" class="flex items-center justify-between px-4 py-1 leading-tight"
> >
<div class="w-5/12 text-left capitalize">{{ league.name.toLowerCase() }}</div> <div class="w-5/12 text-left capitalize">{{ league.name.toLowerCase() }}</div>
<div <div :class="calculateWinrate(league.wins, league.count).color" class="w-3/12">
:class="calculateWinrate(league.wins, league.count).color" {{ calculateWinrate(league.wins, league.count).winrate | percent }}
class="w-3/12" </div>
>{{ calculateWinrate(league.wins, league.count).winrate|percent }}</div>
<div class="w-4/12"> <div class="w-4/12">
<span <span :class="winLossColor(league.wins, league.losses).win" class="font-semibold">{{
:class="winLossColor(league.wins, league.losses).win" league.wins
class="font-semibold" }}</span>
>{{ league.wins }}</span>
<span class="mx-1 font-semibold text-gray-400">-</span> <span class="mx-1 font-semibold text-gray-400">-</span>
<span <span :class="winLossColor(league.wins, league.losses).loss" class="font-semibold">{{
:class="winLossColor(league.wins, league.losses).loss" league.losses
class="font-semibold" }}</span>
>{{ league.losses }}</span>
</div> </div>
</li> </li>
</ul> </ul>
</template> </template>
<template v-if="leagueStatsByType('Normal').length"> <template v-if="leagueStatsByType('Normal').length">
<div class="flex items-baseline px-4 mt-3 text-xs font-semibold text-blue-300 uppercase"> <div class="mt-3 flex items-baseline px-4 text-xs font-semibold uppercase text-blue-300">
<div class="w-5/12 text-base text-left text-blue-400">Normal</div> <div class="w-5/12 text-left text-base text-blue-400">Normal</div>
<div class="w-3/12">Winrate</div> <div class="w-3/12">Winrate</div>
<div class="w-4/12">Record</div> <div class="w-4/12">Record</div>
</div> </div>
@ -155,31 +153,28 @@
<li <li
v-for="(league, index) in leagueStatsByType('Normal')" v-for="(league, index) in leagueStatsByType('Normal')"
:key="index" :key="index"
:class="{'bg-blue-760': index % 2 !== 0}" :class="{ 'bg-blue-760': index % 2 !== 0 }"
class="flex items-center justify-between px-4 py-1 leading-tight" class="flex items-center justify-between px-4 py-1 leading-tight"
> >
<div class="w-5/12 text-left capitalize">{{ league.name.toLowerCase() }}</div> <div class="w-5/12 text-left capitalize">{{ league.name.toLowerCase() }}</div>
<div <div :class="calculateWinrate(league.wins, league.count).color" class="w-3/12">
:class="calculateWinrate(league.wins, league.count).color" {{ calculateWinrate(league.wins, league.count).winrate | percent }}
class="w-3/12" </div>
>{{ calculateWinrate(league.wins, league.count).winrate|percent }}</div>
<div class="w-4/12"> <div class="w-4/12">
<span <span :class="winLossColor(league.wins, league.losses).win" class="font-semibold">{{
:class="winLossColor(league.wins, league.losses).win" league.wins
class="font-semibold" }}</span>
>{{ league.wins }}</span>
<span class="mx-1 font-semibold text-gray-400">-</span> <span class="mx-1 font-semibold text-gray-400">-</span>
<span <span :class="winLossColor(league.wins, league.losses).loss" class="font-semibold">{{
:class="winLossColor(league.wins, league.losses).loss" league.losses
class="font-semibold" }}</span>
>{{ league.losses }}</span>
</div> </div>
</li> </li>
</ul> </ul>
</template> </template>
<div class="flex items-baseline px-4 mt-3 text-xs font-semibold text-blue-300 uppercase"> <div class="mt-3 flex items-baseline px-4 text-xs font-semibold uppercase text-blue-300">
<div class="w-5/12 text-base text-left text-blue-400">Class</div> <div class="w-5/12 text-left text-base text-blue-400">Class</div>
<div class="w-3/12">Winrate</div> <div class="w-3/12">Winrate</div>
<div class="w-4/12">Record</div> <div class="w-4/12">Record</div>
</div> </div>
@ -187,43 +182,45 @@
<li <li
v-for="(championClass, index) in stats.class" v-for="(championClass, index) in stats.class"
:key="index" :key="index"
:class="{'bg-blue-760': index % 2 !== 0}" :class="{ 'bg-blue-760': index % 2 !== 0 }"
class="flex items-center justify-between px-4 py-1 leading-tight" class="flex items-center justify-between px-4 py-1 leading-tight"
> >
<div class="w-5/12 text-left capitalize">{{ championClass.id }}</div> <div class="w-5/12 text-left capitalize">{{ championClass.id }}</div>
<div <div
:class="calculateWinrate(championClass.wins, championClass.count).color" :class="calculateWinrate(championClass.wins, championClass.count).color"
class="w-3/12" class="w-3/12"
>{{ calculateWinrate(championClass.wins, championClass.count).winrate|percent }}</div> >
{{ calculateWinrate(championClass.wins, championClass.count).winrate | percent }}
</div>
<div class="w-4/12"> <div class="w-4/12">
<span <span
:class="winLossColor(championClass.wins, championClass.losses).win" :class="winLossColor(championClass.wins, championClass.losses).win"
class="font-semibold" class="font-semibold"
>{{ championClass.wins }}</span> >{{ championClass.wins }}</span
>
<span class="mx-1 font-semibold text-gray-400">-</span> <span class="mx-1 font-semibold text-gray-400">-</span>
<span <span
:class="winLossColor(championClass.wins, championClass.losses).loss" :class="winLossColor(championClass.wins, championClass.losses).loss"
class="font-semibold" class="font-semibold"
>{{ championClass.losses }}</span> >{{ championClass.losses }}</span
>
</div> </div>
</li> </li>
</ul> </ul>
</div> </div>
<div class="flex flex-col items-center pb-2 leading-snug"> <div class="flex flex-col items-center pb-2 leading-snug">
<div <div class="text-xl text-teal-400">
class="text-xl text-teal-400" {{ calculateWinrate(stats.global.wins, stats.global.count).winrate | percent }}
>{{ calculateWinrate(stats.global.wins, stats.global.count).winrate|percent }}</div> </div>
<div class="flex text-sm"> <div class="flex text-sm">
<span <span :class="winLossColor(stats.global.wins, stats.global.losses).win" class>{{
:class="winLossColor(stats.global.wins, stats.global.losses).win" stats.global.wins
class }}</span>
>{{ stats.global.wins }}</span>
<span class="mx-1 font-bold text-gray-400">-</span> <span class="mx-1 font-bold text-gray-400">-</span>
<span <span :class="winLossColor(stats.global.wins, stats.global.losses).loss" class>{{
:class="winLossColor(stats.global.wins, stats.global.losses).loss" stats.global.losses
class }}</span>
>{{ stats.global.losses }}</span>
</div> </div>
<span class="text-xs">Global winrate</span> <span class="text-xs">Global winrate</span>
</div> </div>
@ -242,7 +239,7 @@ export default {
computed: { computed: {
mostPlayedRole() { mostPlayedRole() {
return Math.max(...this.stats.role.map(r => r.count), 0) return Math.max(...this.stats.role.map((r) => r.count), 0)
}, },
globalStatsKeys() { globalStatsKeys() {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
@ -250,25 +247,25 @@ export default {
return rest return rest
}, },
...mapState({ ...mapState({
stats: state => state.summoner.overview.stats stats: (state) => state.summoner.overview.stats,
}), }),
}, },
methods: { methods: {
calculateWinrate(wins, count) { calculateWinrate(wins, count) {
const winrate = count !== 0 ? wins / count * 100 : 0 const winrate = count !== 0 ? (wins / count) * 100 : 0
const color = winrate >= 50 ? 'text-green-400' : 'text-red-400' const color = winrate >= 50 ? 'text-green-400' : 'text-red-400'
return { return {
winrate, winrate,
color color,
} }
}, },
leagueStatsByType(typeName) { leagueStatsByType(typeName) {
return this.stats.league return this.stats.league
.map(l => { .map((l) => {
return { ...l, ...gameModes[l.id] } return { ...l, ...gameModes[l.id] }
}) })
.filter(l => l.type === typeName) .filter((l) => l.type === typeName)
}, },
roundedRoleLosses(win, count) { roundedRoleLosses(win, count) {
return win === count ? 'rounded-full' : 'rounded-b-full' return win === count ? 'rounded-full' : 'rounded-b-full'
@ -279,11 +276,11 @@ export default {
winLossColor(win, loss) { winLossColor(win, loss) {
const colors = { const colors = {
win: 'text-gray-200', win: 'text-gray-200',
loss: 'text-gray-200' loss: 'text-gray-200',
} }
win >= loss ? colors.win = 'text-green-400' : colors.loss = 'text-red-400' win >= loss ? (colors.win = 'text-green-400') : (colors.loss = 'text-red-400')
return colors return colors
} },
} },
} }
</script> </script>

View file

@ -1,14 +1,14 @@
<template> <template>
<div> <div>
<div class="inline-block bg-blue-800 rounded-lg"> <div class="inline-block rounded-lg bg-blue-800">
<div <div
class="relative flex items-center justify-center py-2 text-blue-200 rounded-t-lg heading" class="heading relative flex items-center justify-center rounded-t-lg py-2 text-blue-200"
> >
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#time" /> <use xlink:href="#time" />
</svg> </svg>
<span class="mx-3 text-sm font-bold uppercase">Recent Activity</span> <span class="mx-3 text-sm font-bold uppercase">Recent Activity</span>
<svg class="w-4 h-4"> <svg class="h-4 w-4">
<use xlink:href="#time" /> <use xlink:href="#time" />
</svg> </svg>
</div> </div>
@ -19,7 +19,7 @@
<span class="ml-16 text-xs font-semibold text-blue-200">{{ gridDays[73].month }}</span> <span class="ml-16 text-xs font-semibold text-blue-200">{{ gridDays[73].month }}</span>
<span class="ml-16 text-xs font-semibold text-blue-200">{{ gridDays[104].month }}</span> <span class="ml-16 text-xs font-semibold text-blue-200">{{ gridDays[104].month }}</span>
</div> </div>
<div class="flex mt-1"> <div class="mt-1 flex">
<div class="flex flex-col"> <div class="flex flex-col">
<span class="text-xs font-semibold leading-snug text-blue-200">Mo</span> <span class="text-xs font-semibold leading-snug text-blue-200">Mo</span>
<span class="mt-1 text-xs font-semibold leading-snug text-blue-200">Tu</span> <span class="mt-1 text-xs font-semibold leading-snug text-blue-200">Tu</span>
@ -30,20 +30,20 @@
<span class="mt-1 text-xs font-semibold leading-snug text-blue-200">Su</span> <span class="mt-1 text-xs font-semibold leading-snug text-blue-200">Su</span>
</div> </div>
<div <div
class="flex flex-col flex-wrap ml-1" class="ml-1 flex flex-col flex-wrap"
style="width: calc(20px * 15); height: calc(20px * 7)" style="width: calc(20px * 15); height: calc(20px * 7)"
> >
<Tooltip v-for="(day, index) in gridDays.slice(indexFirstMonday)" :key="day.timestamp"> <Tooltip v-for="(day, index) in gridDays.slice(indexFirstMonday)" :key="day.timestamp">
<template #trigger> <template #trigger>
<div <div
:class="[getCaseMargin(index), getCaseColor(day.matches)]" :class="[getCaseMargin(index), getCaseColor(day.matches)]"
class="w-4 h-4 ml-1 cursor-pointer" class="ml-1 h-4 w-4 cursor-pointer"
/> />
</template> </template>
<template #default> <template #default>
<div class="px-2 text-xs text-center text-blue-200 leading-5"> <div class="px-2 text-center text-xs leading-5 text-blue-200">
<div> <div>
<span class="text-white font-semibold">{{ day.date }}</span> <span class="font-semibold text-white">{{ day.date }}</span>
<span>: </span> <span>: </span>
<span class="font-bold text-teal-400">{{ day.matches }}</span> <span class="font-bold text-teal-400">{{ day.matches }}</span>
<span> {{ day.matches > 1 ? 'games' : 'game' }}</span> <span> {{ day.matches > 1 ? 'games' : 'game' }}</span>
@ -51,12 +51,12 @@
<template v-if="day.matches > 0"> <template v-if="day.matches > 0">
<div> <div>
<span>time played: </span> <span>time played: </span>
<span class="font-semibold text-white">{{ day.time|secToHours }}</span> <span class="font-semibold text-white">{{ day.time | secToHours }}</span>
</div> </div>
<div> <div>
<span>record: </span> <span>record: </span>
<span class="font-bold text-green-400">{{ day.wins }}</span> <span class="font-bold text-green-400">{{ day.wins }}</span>
<span> - </span> <span> - </span>
<span class="font-bold text-red-400">{{ day.losses }}</span> <span class="font-bold text-red-400">{{ day.losses }}</span>
</div> </div>
</template> </template>
@ -87,21 +87,21 @@ export default {
options: { options: {
year: 'numeric', year: 'numeric',
month: '2-digit', month: '2-digit',
day: 'numeric' day: 'numeric',
} },
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
recentActivity: state => state.summoner.basic.recentActivity recentActivity: (state) => state.summoner.basic.recentActivity,
}), }),
}, },
watch: { watch: {
recentActivity() { recentActivity() {
this.fillGrid() this.fillGrid()
} },
}, },
created() { created() {
@ -125,7 +125,7 @@ export default {
wins: 0, wins: 0,
losses: 0, losses: 0,
day: day.toLocaleString('en', { weekday: 'long' }).substring(0, 2), day: day.toLocaleString('en', { weekday: 'long' }).substring(0, 2),
month: day.toLocaleString('en', { month: 'long' }).substring(0, 3) month: day.toLocaleString('en', { month: 'long' }).substring(0, 3),
}) })
} }
@ -137,9 +137,7 @@ export default {
const matchTime = new Date(match.day) const matchTime = new Date(match.day)
const formattedTime = matchTime.toLocaleString(undefined, this.options) const formattedTime = matchTime.toLocaleString(undefined, this.options)
const dayOfTheMatch = this.gridDays.filter( const dayOfTheMatch = this.gridDays.filter((e) => e.date === formattedTime)
e => e.date === formattedTime
)
if (dayOfTheMatch.length > 0) { if (dayOfTheMatch.length > 0) {
dayOfTheMatch[0].time = match.time dayOfTheMatch[0].time = match.time
dayOfTheMatch[0].matches = match.wins + match.losses dayOfTheMatch[0].matches = match.wins + match.losses
@ -149,7 +147,7 @@ export default {
} }
// Get the index of the first Monday // Get the index of the first Monday
this.indexFirstMonday = this.gridDays.findIndex(d => d.day === 'Mo') this.indexFirstMonday = this.gridDays.findIndex((d) => d.day === 'Mo')
}, },
getCaseColor(nbMatches) { getCaseColor(nbMatches) {
/* TODO: change this */ /* TODO: change this */
@ -168,7 +166,7 @@ export default {
if (index % 7 !== 0) { if (index % 7 !== 0) {
return 'mt-1' return 'mt-1'
} }
} },
} },
} }
</script> </script>

View file

@ -3,36 +3,39 @@
@mouseenter="hover = true" @mouseenter="hover = true"
@mouseleave="hover = false" @mouseleave="hover = false"
:style="{ :style="{
backgroundImage: backgroundImage: `${hover ? gradientHover : gradient},
`${hover ? gradientHover : gradient}, url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-splashes/${
url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-splashes/${record.champion_id}/${record.champion_id}000.jpg')` record.champion_id
}/${record.champion_id}000.jpg')`,
}" }"
:class="borderColor" :class="borderColor"
class="relative w-full p-4 mx-2 mt-6 leading-none bg-center bg-cover border rounded-lg record-card" class="record-card relative mx-2 mt-6 w-full rounded-lg border bg-cover bg-center p-4 leading-none"
> >
<div <div
:class="[ :class="[
{'bg-blue-1000 bg-opacity-75': hover}, { 'bg-blue-1000 bg-opacity-75': hover },
title.length > 15 ? 'text-sm' : 'text-base' title.length > 15 ? 'text-sm' : 'text-base',
]" ]"
:style="{borderColor: hover ? color : 'transparent'}" :style="{ borderColor: hover ? color : 'transparent' }"
class="absolute top-0 left-0 px-3 py-2 mt-2 ml-2 font-medium leading-4 transition-colors duration-500 ease-in-out border border-transparent rounded-md" class="absolute left-0 top-0 ml-2 mt-2 rounded-md border border-transparent px-3 py-2 font-medium leading-4 transition-colors duration-500 ease-in-out"
> >
<span :class="textColor" class="ml-0">{{ title }}</span> <span :class="textColor" class="ml-0">{{ title }}</span>
</div> </div>
<img <img
:src="`https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${record.champion_id}.png`" :src="`https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${record.champion_id}.png`"
:class="[{'opacity-0 scale-125': hover}, borderColor]" :class="[{ 'scale-125 opacity-0': hover }, borderColor]"
class="block w-16 h-16 mx-auto mt-10 transition duration-500 ease-in transform border-2 rounded-full" class="mx-auto mt-10 block h-16 w-16 transform rounded-full border-2 transition duration-500 ease-in"
alt="Champion Played" alt="Champion Played"
/> />
<div :style="{textShadow: `-2px 1px 6px ${color}`}" class="mt-6 text-4xl">{{ record.amount }}</div> <div :style="{ textShadow: `-2px 1px 6px ${color}` }" class="mt-6 text-4xl">
{{ record.amount }}
</div>
<div class="text-sm"> <div class="text-sm">
<div class="mt-6"> <div class="mt-6">
<span <span :class="record.result ? 'text-green-400' : 'text-red-400'">{{
:class="record.result ? 'text-green-400' : 'text-red-400'" record.result ? 'Won' : 'Lost'
>{{ record.result ? 'Won' : 'Lost' }}</span> }}</span>
<span class="ml-1 font-semibold">{{ timeDifference(record.date) }}</span> <span class="ml-1 font-semibold">{{ timeDifference(record.date) }}</span>
</div> </div>
<div class="mt-2 text-gray-500"> <div class="mt-2 text-gray-500">
@ -40,7 +43,7 @@
<span class="font-semibold text-white">{{ record.champion.name }}</span> <span class="font-semibold text-white">{{ record.champion.name }}</span>
</div> </div>
</div> </div>
<div class="mt-6 text-xs font-light text-right text-gray-200 opacity-25"> <div class="mt-6 text-right text-xs font-light text-gray-200 opacity-25">
<span v-if="hover">{{ record.id }}</span> <span v-if="hover">{{ record.id }}</span>
<span v-else>{{ gameModes[record.gamemode].name }}</span> <span v-else>{{ gameModes[record.gamemode].name }}</span>
</div> </div>
@ -55,38 +58,40 @@ export default {
props: { props: {
borderColor: { borderColor: {
type: String, type: String,
required: true required: true,
}, },
color: { color: {
type: String, type: String,
required: true required: true,
}, },
textColor: { textColor: {
type: String, type: String,
required: true required: true,
}, },
record: { record: {
type: Object, type: Object,
required: true required: true,
}, },
title: { title: {
type: String, type: String,
required: true required: true,
}, },
}, },
data() { data() {
return { return {
gradient: 'linear-gradient(180deg, rgba(42, 67, 101, 0.8) 0%, rgba(42, 67, 101, 0.95) 60%, rgba(42, 67, 101, 1) 100%)', gradient:
gradientHover: 'linear-gradient(rgba(42, 67, 101, 0.1) 0%, rgba(42, 67, 101, 0.3) 60%, rgba(42, 67, 101, 0.5) 100%)', 'linear-gradient(180deg, rgba(42, 67, 101, 0.8) 0%, rgba(42, 67, 101, 0.95) 60%, rgba(42, 67, 101, 1) 100%)',
gradientHover:
'linear-gradient(rgba(42, 67, 101, 0.1) 0%, rgba(42, 67, 101, 0.3) 60%, rgba(42, 67, 101, 0.5) 100%)',
hover: false, hover: false,
gameModes, gameModes,
} }
}, },
methods: { methods: {
timeDifference timeDifference,
} },
} }
</script> </script>

View file

@ -1,64 +1,67 @@
<template> <template>
<div class="flex items-center ml-2 leading-none"> <div class="ml-2 flex items-center leading-none">
<div class="flex flex-col justify-center ml-1"> <div class="ml-1 flex flex-col justify-center">
<div class="flex items-center"> <div class="flex items-center">
<div <div
ref="leagueBorder" ref="leagueBorder"
:style="{backgroundColor: colorBorder}" :style="{ backgroundColor: colorBorder }"
class="relative flex items-center justify-center w-12 h-12 rounded-full percentage-circle" class="percentage-circle relative flex h-12 w-12 items-center justify-center rounded-full"
> >
<div class="relative p-1 bg-blue-900 rounded-full w-11 h-11"> <div class="relative h-11 w-11 rounded-full bg-blue-900 p-1">
<div <div
class="h-full bg-center bg-cover mt-2px" class="mt-0.5 h-full bg-cover bg-center"
:style="{backgroundImage: `url(${selectedLeague.rankImgLink})`}" :style="{ backgroundImage: `url(${selectedLeague.rankImgLink})` }"
></div> ></div>
</div> </div>
</div> </div>
<div <div class="ml-2 text-3xl font-bold uppercase text-teal-500">
class="ml-2 text-3xl font-bold text-teal-500 uppercase" {{ selectedLeague.fullRank }}
>{{ selectedLeague.fullRank }}</div> </div>
<div class="ml-4 text-2xl font-bold">{{ selectedLeague.leaguePoints }} LP</div> <div class="ml-4 text-2xl font-bold">{{ selectedLeague.leaguePoints }} LP</div>
<div <div
v-if="selectedLeague.miniSeries" v-if="selectedLeague.miniSeries"
class="flex items-center p-2 ml-2 bg-blue-800 rounded" class="ml-2 flex items-center rounded bg-blue-800 p-2"
> >
<div <div
v-for="(result, index) in bo" v-for="(result, index) in bo"
:key="index + result" :key="index + result"
:class="[{'ml-1': index !== 0}, boGame(result)]" :class="[{ 'ml-1': index !== 0 }, boGame(result)]"
class="w-3 h-3 rounded-full" class="h-3 w-3 rounded-full"
></div> ></div>
</div> </div>
</div> </div>
<div class="flex items-center mt-2"> <div class="mt-2 flex items-center">
<div class="relative inline-block text-white"> <div class="relative inline-block text-white">
<select <select
v-model="selectedKey" v-model="selectedKey"
class="block w-full px-4 py-2 pr-8 text-lg font-bold leading-tight bg-blue-800 rounded-md appearance-none cursor-pointer hover:bg-blue-700 focus:outline-none" class="block w-full cursor-pointer appearance-none rounded-md bg-blue-800 px-4 py-2 pr-8 text-lg font-bold leading-tight hover:bg-blue-700 focus:outline-none"
> >
<option <option v-for="(data, leagueName) in ranked" :key="leagueName" :value="leagueName">
v-for="(data, leagueName) in ranked" {{ data.name }}
:key="leagueName" </option>
:value="leagueName"
>{{ data.name }}</option>
</select> </select>
<div <div
class="absolute inset-y-0 right-0 flex items-center px-2 text-gray-700 pointer-events-none" class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
> >
<svg class="w-5 h-5 text-white"> <svg class="h-5 w-5 text-white">
<use xlink:href="#chevron-down" /> <use xlink:href="#chevron-down" />
</svg> </svg>
</div> </div>
</div> </div>
<div class="flex items-center p-2 ml-2 bg-blue-800 rounded"> <div class="ml-2 flex items-center rounded bg-blue-800 p-2">
<div class="text-base font-semibold uppercase">Record</div> <div class="text-base font-semibold uppercase">Record</div>
<div class="ml-2 font-semibold text-green-400">{{ selectedLeague.wins }}</div> <div class="ml-2 font-semibold text-green-400">{{ selectedLeague.wins }}</div>
<span class="mx-1">-</span> <span class="mx-1">-</span>
<div class="font-semibold text-red-400">{{ selectedLeague.losses }}</div> <div class="font-semibold text-red-400">{{ selectedLeague.losses }}</div>
<div class="ml-3 text-base font-semibold uppercase">Winrate</div> <div class="ml-3 text-base font-semibold uppercase">Winrate</div>
<div <div
:class="['ml-2 text-base leading-tight font-semibold', parseFloat(selectedLeague.winrate) >= 50 ? 'text-green-400' : 'text-red-400']" :class="[
>{{ selectedLeague.winrate }}</div> 'ml-2 text-base font-semibold leading-tight',
parseFloat(selectedLeague.winrate) >= 50 ? 'text-green-400' : 'text-red-400',
]"
>
{{ selectedLeague.winrate }}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -70,24 +73,24 @@ export default {
props: { props: {
ranked: { ranked: {
type: Object, type: Object,
required: true required: true,
} },
}, },
data() { data() {
return { return {
currentDegree: 0, currentDegree: 0,
rankColors: { rankColors: {
'iron': '#574D4F', iron: '#574D4F',
'bronze': '#8C523A', bronze: '#8C523A',
'silver': '#80989D', silver: '#80989D',
'gold': '#CD8837', gold: '#CD8837',
'platinum': '#4E9996', platinum: '#4E9996',
'diamond': '#576BCE', diamond: '#576BCE',
'master': '#9D48E0', master: '#9D48E0',
'grandmaster': '#CD4545', grandmaster: '#CD4545',
'challenger': '#F4C874', challenger: '#F4C874',
}, },
selectedKey: Object.keys(this.ranked)[0] selectedKey: Object.keys(this.ranked)[0],
} }
}, },
@ -102,11 +105,14 @@ export default {
return this.rankColors[this.selectedLeague.tier.toLowerCase()] return this.rankColors[this.selectedLeague.tier.toLowerCase()]
}, },
leagueDegrees() { leagueDegrees() {
return (this.selectedLeague.leaguePoints <= 100 ? this.selectedLeague.leaguePoints : 100) * 360 / 100 return (
((this.selectedLeague.leaguePoints <= 100 ? this.selectedLeague.leaguePoints : 100) * 360) /
100
)
}, },
selectedLeague() { selectedLeague() {
return this.ranked[this.selectedKey] return this.ranked[this.selectedKey]
} },
}, },
watch: { watch: {
@ -114,7 +120,7 @@ export default {
this.currentDegree = 0 this.currentDegree = 0
this.$refs.leagueBorder.style.backgroundImage = null this.$refs.leagueBorder.style.backgroundImage = null
this.triggerAnimation() this.triggerAnimation()
} },
}, },
mounted() { mounted() {
@ -124,10 +130,14 @@ export default {
methods: { methods: {
animateLeagueDegrees(stop = false) { animateLeagueDegrees(stop = false) {
if (stop || !this.$refs.leagueBorder) return if (stop || !this.$refs.leagueBorder) return
this.selectedLeague.leaguePoints > 50 ? this.currentDegree += 2 : this.currentDegree++ this.selectedLeague.leaguePoints > 50 ? (this.currentDegree += 2) : this.currentDegree++
const linearGradient =
const linearGradient = this.currentDegree <= 180 ? `linear-gradient(${90 + this.currentDegree}deg, transparent 50%, #2c5282 50%)` : `linear-gradient(${this.currentDegree - 90}deg, transparent 50%, ${this.colorBorder} 50%)` this.currentDegree <= 180
? `linear-gradient(${90 + this.currentDegree}deg, transparent 50%, #2c5282 50%)`
: `linear-gradient(${this.currentDegree - 90}deg, transparent 50%, ${
this.colorBorder
} 50%)`
this.$refs.leagueBorder.style.backgroundImage = `${linearGradient}, linear-gradient(90deg, #2c5282 50%, transparent 50%)` this.$refs.leagueBorder.style.backgroundImage = `${linearGradient}, linear-gradient(90deg, #2c5282 50%, transparent 50%)`
this.triggerAnimation() this.triggerAnimation()
@ -146,10 +156,9 @@ export default {
setTimeout(() => { setTimeout(() => {
if (this.currentDegree < 360 && this.currentDegree < this.leagueDegrees) if (this.currentDegree < 360 && this.currentDegree < this.leagueDegrees)
this.animateLeagueDegrees() this.animateLeagueDegrees()
else else this.animateLeagueDegrees(true)
this.animateLeagueDegrees(true)
}, 1) }, 1)
} },
} },
} }
</script> </script>

View file

@ -3,7 +3,7 @@ export const maps = { 10: 'The Twisted Treeline', 11: "Summoner's Rift", 12: 'Ho
export const gameModes = { export const gameModes = {
0: { 0: {
type: 'Custom', type: 'Custom',
name: 'Custom Game' name: 'Custom Game',
}, },
900: { 900: {
type: 'Normal', type: 'Normal',
@ -75,20 +75,20 @@ export const gameModes = {
}, },
1020: { 1020: {
type: 'Normal', type: 'Normal',
name: 'One for All' name: 'One for All',
}, },
1300: { 1300: {
type: 'Normal', type: 'Normal',
name: 'Nexus Blitz' name: 'Nexus Blitz',
}, },
1400: { 1400: {
type: 'Normal', type: 'Normal',
name: 'Ultimate Spellbook' name: 'Ultimate Spellbook',
}, },
1900: { 1900: {
type: 'Normal', type: 'Normal',
name: 'URF', name: 'URF',
} },
} }
/* ========= OLD 5 COLORS ========= */ /* ========= OLD 5 COLORS ========= */

View file

@ -1,6 +1,6 @@
/** /**
* Return the relative time betweeen a chosen moment and the current time * Return the relative time betweeen a chosen moment and the current time
* @param previous : time we want to get difference * @param previous : time we want to get difference
*/ */
export function timeDifference(previous) { export function timeDifference(previous) {
const current = new Date() const current = new Date()
@ -26,13 +26,13 @@ export function timeDifference(previous) {
/** /**
* Convert seconds to a readable string * Convert seconds to a readable string
* @param {Number} seconds * @param {Number} seconds
*/ */
export function secToTime(seconds) { export function secToTime(seconds) {
const min = Math.floor(seconds / 60) const min = Math.floor(seconds / 60)
let newSec = Math.floor(seconds - min * 60) let newSec = Math.floor(seconds - min * 60)
newSec = newSec < 10 ? '0' + newSec : newSec newSec = newSec < 10 ? '0' + newSec : newSec
return `${min}:${newSec}` return `${min}:${newSec}`
} }
@ -46,7 +46,7 @@ export function sortTeamByRole(a, b) {
/** /**
* Give the full CDragon image path from the iconPath field * Give the full CDragon image path from the iconPath field
* @param {String} iconPath * @param {String} iconPath
*/ */
export function createCDragonAssetUrl(iconPath) { export function createCDragonAssetUrl(iconPath) {
const name = iconPath.split('/assets/')[1].toLowerCase() const name = iconPath.split('/assets/')[1].toLowerCase()

View file

@ -7,7 +7,9 @@ import store from '@/store'
* @param {Object} perks : from the API * @param {Object} perks : from the API
*/ */
export function getPrimarRune(perks) { export function getPrimarRune(perks) {
const primaryRune = perks.selected.length ? store.state.cdragon.runes.perks[perks.selected[0]] : null const primaryRune = perks.selected.length
? store.state.cdragon.runes.perks[perks.selected[0]]
: null
return primaryRune ? createCDragonAssetUrl(primaryRune.icon) : null return primaryRune ? createCDragonAssetUrl(primaryRune.icon) : null
} }
@ -17,7 +19,7 @@ export function getPrimarRune(perks) {
*/ */
export function getSecondaryRune(perks) { export function getSecondaryRune(perks) {
const secondaryRune = store.state.cdragon.runes.perkstyles[perks.secondaryStyle] const secondaryRune = store.state.cdragon.runes.perkstyles[perks.secondaryStyle]
return secondaryRune ? createCDragonAssetUrl(secondaryRune.icon) : null return secondaryRune ? createCDragonAssetUrl(secondaryRune.icon) : null
} }
/** /**
@ -33,7 +35,10 @@ export function createMatchData(matches) {
const date = new Date(match.date) const date = new Date(match.date)
const dateOptions = { day: '2-digit', month: '2-digit', year: 'numeric' } const dateOptions = { day: '2-digit', month: '2-digit', year: 'numeric' }
const timeOptions = { hour12: false, hour: '2-digit', minute: '2-digit' } const timeOptions = { hour12: false, hour: '2-digit', minute: '2-digit' }
match.fullDate = { date: date.toLocaleString(undefined, dateOptions), time: date.toLocaleString(undefined, timeOptions) } match.fullDate = {
date: date.toLocaleString(undefined, dateOptions),
time: date.toLocaleString(undefined, timeOptions),
}
match.date = timeDifference(match.date) match.date = timeDifference(match.date)
match.map = maps[match.map] match.map = maps[match.map]
@ -70,7 +75,7 @@ export function createBasicSummonerData(summonerBasic) {
wins: 0, wins: 0,
losses: 0, losses: 0,
winrate: '0%', winrate: '0%',
name: 'Solo/Duo' name: 'Solo/Duo',
} }
} }
@ -88,7 +93,7 @@ export function createRecordsData(recordsDto) {
}, {}) }, {})
records.game_duration.amount = secToTime(records.game_duration.amount) records.game_duration.amount = secToTime(records.game_duration.amount)
records.gold.amount = records.gold.amount.toLocaleString() records.gold.amount = records.gold.amount.toLocaleString()
records.damage_taken.amount = records.damage_taken.amount.toLocaleString() records.damage_taken.amount = records.damage_taken.amount.toLocaleString()
records.damage_dealt_champions.amount = records.damage_dealt_champions.amount.toLocaleString() records.damage_dealt_champions.amount = records.damage_dealt_champions.amount.toLocaleString()
records.damage_dealt_objectives.amount = records.damage_dealt_objectives.amount.toLocaleString() records.damage_dealt_objectives.amount = records.damage_dealt_objectives.amount.toLocaleString()
@ -101,8 +106,8 @@ export function createRecordsData(recordsDto) {
/** /**
* Add rank img and ranked data * Add rank img and ranked data
* @param {Object} leagueData * @param {Object} leagueData
* @param {String} leagueName * @param {String} leagueName
*/ */
function getLeagueData(leagueData, leagueName) { function getLeagueData(leagueData, leagueName) {
if (!leagueData) return null if (!leagueData) return null

View file

@ -1,21 +1,21 @@
<template> <template>
<div class="flex flex-col min-h-screen overflow-hidden bg-blue-900"> <div class="flex min-h-screen flex-col overflow-hidden bg-blue-900">
<LazyBackground <LazyBackground
:image-source="require('@/assets/img/bg-homepage-1.jpg')" image-source="/img/bg-homepage-1.jpg"
image-class="absolute z-0 w-full h-200" image-class="absolute z-0 w-full h-[50rem]"
more-backgrounds="linear-gradient(180deg, rgba(42, 67, 101, 0) 0%, #2A4365 50%)," more-backgrounds="linear-gradient(180deg, rgba(42, 67, 101, 0) 0%, #2A4365 50%),"
transition-name="fade" transition-name="fade"
></LazyBackground> ></LazyBackground>
<header <header
:class="bgHeader ? 'header-scrolled' : 'bg-transparent'" :class="bgHeader ? 'header-scrolled' : 'bg-transparent'"
class="fixed left-0 right-0 z-20 px-4 text-teal-100 transition-colors duration-100 ease-in-out border-b-2 header" class="header fixed left-0 right-0 z-20 border-b-2 px-4 text-teal-100 transition-colors duration-100 ease-in-out"
style="border-color: rgba(144, 205, 244, 0.4);" style="border-color: rgba(144, 205, 244, 0.4)"
> >
<div class="flex items-center justify-between py-2 -mb-2px"> <div class="-mb-0.5 flex items-center justify-between py-2">
<div class="flex flex-1"> <div class="flex flex-1">
<router-link to="/"> <router-link to="/">
<img class="block h-10" src="@/assets/img/Logo.svg" alt="LeagueStats logo" /> <img class="block h-10" src="/img/Logo.svg" alt="LeagueStats logo" />
</router-link> </router-link>
</div> </div>
@ -23,7 +23,7 @@
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center justify-end"> <div class="flex items-center justify-end">
<a class="relative text-sm discord" href="https://discord.gg/RjBzjfk" target="_blank"> <a class="discord relative text-sm" href="https://discord.gg/RjBzjfk" target="_blank">
<svg <svg
class="absolute fill-current" class="absolute fill-current"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -44,7 +44,7 @@
</div> </div>
</header> </header>
<div class="relative z-10 flex-grow mx-auto mt-20 text-white page-wrapper"> <div class="page-wrapper relative z-10 mx-auto mt-20 flex-grow text-white">
<template v-if="summonerLoading || summonerFound"> <template v-if="summonerLoading || summonerFound">
<template v-if="summonerLoading"> <template v-if="summonerLoading">
<HeaderLoader /> <HeaderLoader />
@ -52,7 +52,7 @@
<template v-else-if="summonerFound"> <template v-else-if="summonerFound">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
<div class="flex items-center mt-2"> <div class="mt-2 flex items-center">
<Tooltip> <Tooltip>
<template #trigger> <template #trigger>
<h1 class="text-4xl font-extrabold"> <h1 class="text-4xl font-extrabold">
@ -62,47 +62,53 @@
<template #default> <template #default>
<div <div
v-if="basic.account.names.length > 1" v-if="basic.account.names.length > 1"
class="px-2 text-sm text-center text-white select-none" class="select-none px-2 text-center text-sm text-white"
> >
<div>Old summoner names</div> <div>Old summoner names</div>
<ul class="pl-2 text-left list-disc list-inside"> <ul class="list-inside list-disc pl-2 text-left">
<li <li
v-for="name in basic.account.names.slice(0, -1)" v-for="name in basic.account.names.slice(0, -1)"
:key="name.date" :key="name.date"
class="text-teal-400" class="text-teal-400"
>{{ name.name }}</li> >
{{ name.name }}
</li>
</ul> </ul>
</div> </div>
</template> </template>
</Tooltip> </Tooltip>
<div <div
v-if="playing" v-if="playing"
class="flex items-center px-3 py-1 mt-2 ml-4 bg-teal-800 border border-teal-400 rounded-full" class="ml-4 mt-2 flex items-center rounded-full border border-teal-400 bg-teal-800 px-3 py-1"
> >
<div class="w-2 h-2 rounded-full playing-dot bg-teal-flashy"></div> <div class="playing-dot h-2 w-2 rounded-full bg-teal-flashy"></div>
<span class="ml-2 text-sm font-semibold text-teal-flashy">In Game</span> <span class="ml-2 text-sm font-semibold text-teal-flashy">In Game</span>
</div> </div>
<div <div
v-if="false" v-if="false"
class="inline-flex items-center px-2 py-1 mt-2 ml-4 leading-tight border border-teal-500 rounded" class="ml-4 mt-2 inline-flex items-center rounded border border-teal-500 px-2 py-1 leading-tight"
style="background: rgba(40, 94, 97, 0.35);" style="background: rgba(40, 94, 97, 0.35)"
> >
<svg class="w-4 h-4 text-teal-600"> <svg class="h-4 w-4 text-teal-600">
<use xlink:href="#star" /> <use xlink:href="#star" />
</svg> </svg>
<div class="ml-1 text-xs font-bold text-teal-200">Favorite</div> <div class="ml-1 text-xs font-bold text-teal-200">Favorite</div>
</div> </div>
</div> </div>
<div class="flex mt-2"> <div class="mt-2 flex">
<div :class="{'playing': playing}" class="relative w-24 h-24"> <div :class="{ playing: playing }" class="relative h-24 w-24">
<div <div
:class="{'border-2': !playing}" :class="{ 'border-2': !playing }"
class="relative z-10 w-24 h-24 bg-center bg-cover border-teal-400 rounded-full bg-blue-1000" class="relative z-10 h-24 w-24 rounded-full border-teal-400 bg-blue-1000 bg-cover bg-center"
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/profile-icons/${basic.account.profileIconId}.jpg')`}" :style="{
backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/profile-icons/${basic.account.profileIconId}.jpg')`,
}"
> >
<div <div
class="absolute bottom-0 left-0 flex items-center justify-center w-8 h-8 text-xs font-extrabold text-teal-500 bg-blue-900 border-2 border-teal-400 rounded-full" class="absolute bottom-0 left-0 flex h-8 w-8 items-center justify-center rounded-full border-2 border-teal-400 bg-blue-900 text-xs font-extrabold text-teal-500"
>{{ basic.account.summonerLevel }}</div> >
{{ basic.account.summonerLevel }}
</div>
</div> </div>
</div> </div>
@ -121,29 +127,45 @@
<!-- NAVIGATION --> <!-- NAVIGATION -->
<div class="pb-2"> <div class="pb-2">
<router-link <router-link
:to="{ name: 'summoner', params: { region: $route.params.region, name: $route.params.name }}" :to="{
name: 'summoner',
params: { region: $route.params.region, name: $route.params.name },
}"
:class="isRouteActive('summoner')" :class="isRouteActive('summoner')"
class="pb-2 text-blue-300 border-b-2 border-transparent cursor-pointer hover:text-blue-100" class="cursor-pointer border-b-2 border-transparent pb-2 text-blue-300 hover:text-blue-100"
exact exact
>Overview</router-link> >Overview</router-link
>
<router-link <router-link
:to="{ name: 'summonerChampions', params: { region: $route.params.region, name: $route.params.name }}" :to="{
name: 'summonerChampions',
params: { region: $route.params.region, name: $route.params.name },
}"
:class="isRouteActive('summonerChampions')" :class="isRouteActive('summonerChampions')"
class="pb-2 ml-4 text-blue-300 border-b-2 border-transparent cursor-pointer hover:text-blue-100" class="ml-4 cursor-pointer border-b-2 border-transparent pb-2 text-blue-300 hover:text-blue-100"
exact exact
>Champions</router-link> >Champions</router-link
>
<router-link <router-link
:to="{ name: 'summonerRecords', params: { region: $route.params.region, name: $route.params.name }}" :to="{
name: 'summonerRecords',
params: { region: $route.params.region, name: $route.params.name },
}"
:class="isRouteActive('summonerRecords')" :class="isRouteActive('summonerRecords')"
class="pb-2 ml-4 text-blue-300 border-b-2 border-transparent cursor-pointer hover:text-blue-100" class="ml-4 cursor-pointer border-b-2 border-transparent pb-2 text-blue-300 hover:text-blue-100"
exact exact
>Records</router-link> >Records</router-link
>
<router-link <router-link
:to="{ name: 'summonerLive', params: { region: $route.params.region, name: $route.params.name }}" :to="{
name: 'summonerLive',
params: { region: $route.params.region, name: $route.params.name },
}"
:class="isRouteActive('summonerLive')" :class="isRouteActive('summonerLive')"
class="pb-2 ml-4 text-blue-300 border-b-2 border-transparent cursor-pointer hover:text-blue-100" class="ml-4 cursor-pointer border-b-2 border-transparent pb-2 text-blue-300 hover:text-blue-100"
exact exact
>Live game</router-link> >Live game</router-link
>
</div> </div>
<!-- Select Season --> <!-- Select Season -->
@ -160,8 +182,8 @@
</template> </template>
<template v-else-if="summonerNotFound"> <template v-else-if="summonerNotFound">
<div class="flex justify-center mt-16"> <div class="mt-16 flex justify-center">
<div class="px-4 py-3 text-lg font-bold text-center text-blue-100 rounded-lg bg-gradient"> <div class="bg-gradient rounded-lg px-4 py-3 text-center text-lg font-bold text-blue-100">
<div>Player can't be found.</div> <div>Player can't be found.</div>
<div>😕</div> <div>😕</div>
</div> </div>
@ -193,12 +215,12 @@ export default {
SearchForm, SearchForm,
HeaderLoader, HeaderLoader,
SummonerRanked, SummonerRanked,
Tooltip Tooltip,
}, },
data() { data() {
return { return {
bgHeader: false bgHeader: false,
} }
}, },
@ -207,21 +229,28 @@ export default {
return this.summonerFound && this.overviewLoaded ? 'tab' : 'none' return this.summonerFound && this.overviewLoaded ? 'tab' : 'none'
}, },
...mapState({ ...mapState({
basic: state => state.summoner.basic basic: (state) => state.summoner.basic,
}), }),
...mapGetters('summoner', ['playing', 'overviewLoaded', 'summonerFound', 'summonerNotFound', 'summonerLoading']) ...mapGetters('summoner', [
'playing',
'overviewLoaded',
'summonerFound',
'summonerNotFound',
'summonerLoading',
]),
}, },
watch: { watch: {
$route(to, from) { $route(to, from) {
if (from.params.region === to.params.region && from.params.name === to.params.name) if (from.params.region === to.params.region && from.params.name === to.params.name) return
return
this.apiCall() this.apiCall()
} },
}, },
created() { created() {
this.apiCall() if (this.$route.params.region) {
this.apiCall()
}
window.addEventListener('scroll', this.handleScroll) window.addEventListener('scroll', this.handleScroll)
}, },
@ -239,11 +268,11 @@ export default {
}, },
isRouteActive(currentRoute) { isRouteActive(currentRoute) {
return { return {
'router-link-active': this.$route.name === currentRoute 'router-link-active': this.$route.name === currentRoute,
} }
}, },
redirect(summoner, region) { redirect(summoner, region) {
this.$router.push(`/summoner/${region}/${summoner}`).catch(() => { }) this.$router.push(`/summoner/${region}/${summoner}`).catch(() => {})
}, },
...mapActions('settings', ['updateSettings']), ...mapActions('settings', ['updateSettings']),
...mapActions('summoner', ['basicRequest']), ...mapActions('summoner', ['basicRequest']),
@ -251,9 +280,11 @@ export default {
metaInfo() { metaInfo() {
return { return {
titleTemplate: this.summonerFound ? `${this.basic.account.name} | LeagueStats.gg %s` : 'LeagueStats.gg %s', titleTemplate: this.summonerFound
? `${this.basic.account.name} | LeagueStats.gg %s`
: 'LeagueStats.gg %s',
} }
} },
} }
</script> </script>
@ -290,7 +321,7 @@ export default {
.playing::before, .playing::before,
.playing::after { .playing::after {
content: ""; content: '';
position: absolute; position: absolute;
height: 100px; height: 100px;
width: 100px; width: 100px;
@ -303,11 +334,7 @@ export default {
.playing::after { .playing::after {
z-index: 0; z-index: 0;
background: linear-gradient( background: linear-gradient(to top, rgba(0, 0, 0, 0) 30%, rgb(36, 232, 204) 100%);
to top,
rgba(0, 0, 0, 0) 30%,
rgb(36, 232, 204) 100%
);
animation: 0.75s linear 0s infinite normal none running rotate; animation: 0.75s linear 0s infinite normal none running rotate;
} }

View file

@ -1,11 +1,10 @@
import Vue from 'vue' import Vue from 'vue'
import VueAxios from './plugins/axios' import VueAxios from './plugins/axios'
import VueMeta from 'vue-meta' import VueMeta from 'vue-meta'
import { VuePlausible } from 'vue-plausible' import VuePlausible from './plugins/plausible'
import PortalVue from 'portal-vue' import PortalVue from 'portal-vue'
import './assets/css/main.css'
import '@/assets/css/main.css'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
@ -13,12 +12,7 @@ import store from './store'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(VueAxios) Vue.use(VueAxios)
Vue.use(VuePlausible, { Vue.use(VuePlausible)
domain: 'leaguestats.gg',
trackLocalhost: false,
apiHost: 'https://stats.leaguestats.gg'
})
Vue.$plausible.enableAutoPageviews()
Vue.use(VueMeta) Vue.use(VueMeta)
Vue.use(PortalVue) Vue.use(PortalVue)
@ -45,8 +39,8 @@ Vue.filter('secToHours', (sec) => {
const result = [] const result = []
const d = Math.floor(sec / (3600 * 24)) const d = Math.floor(sec / (3600 * 24))
const h = Math.floor(sec % (3600 * 24) / 3600) const h = Math.floor((sec % (3600 * 24)) / 3600)
const m = Math.floor(sec % 3600 / 60) const m = Math.floor((sec % 3600) / 60)
if (d > 0) { if (d > 0) {
result.push(d + ' days') result.push(d + ' days')
@ -54,7 +48,7 @@ Vue.filter('secToHours', (sec) => {
if (h > 0) { if (h > 0) {
result.push(h + 'h') result.push(h + 'h')
} }
if (m > 0) { if (m > 0) {
result.push(m + 'm') result.push(m + 'm')
} }
@ -76,5 +70,5 @@ Vue.filter('round', (value, decimals = 2) => {
new Vue({ new Vue({
router, router,
store, store,
render: h => h(App), render: (h) => h(App),
}).$mount('#app') }).$mount('#app')

View file

@ -5,7 +5,7 @@ import { mapState } from 'vuex'
export const liveGame = { export const liveGame = {
data() { data() {
return { return {
gameLength: 0 gameLength: 0,
} }
}, },
@ -14,7 +14,9 @@ export const liveGame = {
if (!this.current || !this.current.participants) { if (!this.current || !this.current.participants) {
return [] return []
} }
return this.current.participants.filter(p => p.teamId === this.teamColor).sort(this.sortTeamByRole) return this.current.participants
.filter((p) => p.teamId === this.teamColor)
.sort(this.sortTeamByRole)
}, },
displayStartTime() { displayStartTime() {
if (this.current.gameStartTime === 0) { if (this.current.gameStartTime === 0) {
@ -26,11 +28,15 @@ export const liveGame = {
if (!this.current || !this.current.participants) { if (!this.current || !this.current.participants) {
return [] return []
} }
return this.current.participants.filter(p => p.teamId !== this.teamColor).sort(this.sortTeamByRole) return this.current.participants
.filter((p) => p.teamId !== this.teamColor)
.sort(this.sortTeamByRole)
}, },
gamemode() { gamemode() {
if (this.current.participants) { if (this.current.participants) {
return this.current.gameType === 'CUSTOM_GAME' ? { type: '', name: 'Custom Game' } : gameModes[this.current.gameQueueConfigId] return this.current.gameType === 'CUSTOM_GAME'
? { type: '', name: 'Custom Game' }
: gameModes[this.current.gameQueueConfigId]
} else { } else {
return { type: '', name: '' } return { type: '', name: '' }
} }
@ -39,12 +45,12 @@ export const liveGame = {
return this.current ? this.current.gameStartTime : 0 return this.current ? this.current.gameStartTime : 0
}, },
teamColor() { teamColor() {
return this.current.participants.find(p => p.summonerId === this.account.id).teamId return this.current.participants.find((p) => p.summonerId === this.account.id).teamId
}, },
...mapState({ ...mapState({
account: state => state.summoner.basic.account, account: (state) => state.summoner.basic.account,
current: state => state.summoner.live.match, current: (state) => state.summoner.live.match,
}) }),
}, },
created() { created() {
@ -58,17 +64,17 @@ export const liveGame = {
watch: { watch: {
gameStartTime() { gameStartTime() {
this.updateGameLength() this.updateGameLength()
} },
}, },
methods: { methods: {
updateGameLength() { updateGameLength() {
if (this.gameStartTime === 0) { if (this.gameStartTime === 0) {
return this.gameLength = 0 return (this.gameLength = 0)
} }
this.gameLength = (new Date() - new Date(this.gameStartTime)) / 1000 this.gameLength = (new Date() - new Date(this.gameStartTime)) / 1000
}, },
sortTeamByRole sortTeamByRole,
} },
} }

View file

@ -6,7 +6,9 @@ export const axios = axiosHttp
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest' axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
axios.defaults.headers.common['Content-Type'] = 'application/json' axios.defaults.headers.common['Content-Type'] = 'application/json'
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:3333/' : 'https://api.leaguestats.gg/' axios.defaults.baseURL = import.meta.env.DEV
? 'http://localhost:3333/'
: 'https://api.leaguestats.gg/'
const CancelToken = axios.CancelToken const CancelToken = axios.CancelToken
const axiosSource = CancelToken.source() const axiosSource = CancelToken.source()
@ -15,7 +17,11 @@ axios.defaults.cancelToken = axiosSource.token
// Add season number to data if the route need it // Add season number to data if the route need it
axios.interceptors.request.use(function (config) { axios.interceptors.request.use(function (config) {
if (config.method === 'post' && config.url !== 'summoner/basic' && router.currentRoute.meta.season) { if (
config.method === 'post' &&
config.url !== 'summoner/basic' &&
router.currentRoute.meta.season
) {
config.data.season = store.state.summoner.basic.currentSeason config.data.season = store.state.summoner.basic.currentSeason
} }
return config return config
@ -24,5 +30,5 @@ axios.interceptors.request.use(function (config) {
export default { export default {
install(Vue) { install(Vue) {
Vue.prototype.$axios = axiosHttp Vue.prototype.$axios = axiosHttp
} },
} }

View file

@ -0,0 +1,15 @@
import Plausible from 'plausible-tracker'
export default {
install(Vue) {
const options = {
domain: 'leaguestats.gg',
trackLocalhost: false,
apiHost: 'https://stats.leaguestats.gg',
}
const plausible = Plausible(options)
plausible.enableAutoPageviews()
Vue.prototype.$plausible = plausible
},
}

View file

@ -2,56 +2,50 @@ import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import { axios } from './plugins/axios' import { axios } from './plugins/axios'
import Home from '@/views/Home.vue'
import Summoner from '@/views/Summoner.vue'
import SummonerChampions from '@/views/SummonerChampions.vue'
import SummonerLive from '@/views/SummonerLive.vue'
import SummonerRecords from '@/views/SummonerRecords.vue'
Vue.use(Router) Vue.use(Router)
const router = new Router({ const router = new Router({
mode: 'history', mode: 'history',
base: process.env.BASE_URL, base: import.meta.env.BASE_URL,
routes: [ routes: [
{ {
path: '/', path: '/',
name: 'home', name: 'home',
component: Home, component: () => import('@/views/Home.vue'),
meta: { meta: {
layout: 'Home' layout: 'Home',
} },
}, },
{ {
path: '/summoner/:region/:name', path: '/summoner/:region/:name',
name: 'summoner', name: 'summoner',
component: Summoner, component: () => import('@/views/Summoner.vue'),
meta: { meta: {
season: true season: true,
} },
}, },
{ {
path: '/summoner/:region/:name/champions', path: '/summoner/:region/:name/champions',
name: 'summonerChampions', name: 'summonerChampions',
component: SummonerChampions, component: () => import('@/views/SummonerChampions.vue'),
meta: { meta: {
season: true season: true,
} },
}, },
{ {
path: '/summoner/:region/:name/records', path: '/summoner/:region/:name/records',
name: 'summonerRecords', name: 'summonerRecords',
component: SummonerRecords, component: () => import('@/views/SummonerRecords.vue'),
meta: { meta: {
season: true season: true,
} },
}, },
{ {
path: '/summoner/:region/:name/live', path: '/summoner/:region/:name/live',
name: 'summonerLive', name: 'summonerLive',
component: SummonerLive component: () => import('@/views/SummonerLive.vue'),
}, },
] ],
}) })
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
@ -69,4 +63,4 @@ router.beforeEach((to, from, next) => {
next() next()
}) })
export default router export default router

View file

@ -8,7 +8,7 @@ import * as summoner from '@/store/modules/summoner'
Vue.use(Vuex) Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production' const debug = import.meta.env.DEV
export default new Vuex.Store({ export default new Vuex.Store({
modules: { modules: {
@ -16,28 +16,28 @@ export default new Vuex.Store({
detailedMatch, detailedMatch,
notification, notification,
settings, settings,
summoner summoner,
}, },
state: { state: {
regionsList: { regionsList: {
'br': 'br1', br: 'br1',
'eune': 'eun1', eune: 'eun1',
'euw': 'euw1', euw: 'euw1',
'jp': 'jp1', jp: 'jp1',
'kr': 'kr', kr: 'kr',
'lan': 'la1', lan: 'la1',
'las': 'la2', las: 'la2',
'na': 'na1', na: 'na1',
'oce': 'oc1', oce: 'oc1',
'tr': 'tr1', tr: 'tr1',
'ru': 'ru', ru: 'ru',
'ph': 'ph2', ph: 'ph2',
'sg': 'sg2', sg: 'sg2',
'th': 'th2', th: 'th2',
'tw': 'tw2', tw: 'tw2',
'vn': 'vn2', vn: 'vn2',
}, },
roles: ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY'] roles: ['TOP', 'JUNGLE', 'MIDDLE', 'BOTTOM', 'UTILITY'],
}, },
strict: debug strict: debug,
}) })

View file

@ -14,28 +14,38 @@ export const state = {
} }
export const mutations = { export const mutations = {
DISPLAY_HIDE_RUNES(state, selectedRunes) { DISPLAY_RUNES(state, selectedRunes) {
state.runesOpen = !state.runesOpen state.runesOpen = true
state.selectedRunes = selectedRunes state.selectedRunes = selectedRunes
}, },
HIDE_RUNES(state) {
state.runesOpen = false
},
SET_RUNES(state, runes) { SET_RUNES(state, runes) {
state.runes = runes state.runes = runes
}, },
} }
export const actions = { export const actions = {
displayOrHideRunes({ commit }, selectedRunes) { displayRunes({ commit }, selectedRunes) {
commit('DISPLAY_HIDE_RUNES', selectedRunes) commit('DISPLAY_RUNES', selectedRunes)
},
hideRunes({ commit }) {
commit('HIDE_RUNES')
}, },
async getRunes({ commit, getters }) { async getRunes({ commit, getters }) {
if (getters.runesLoaded) { return } if (getters.runesLoaded) {
return
}
const { data } = await axios.get('cdragon/runes').catch((e) => { console.log(e) }) const { data } = await axios.get('cdragon/runes').catch((e) => {
console.log(e)
})
console.log(data) console.log(data)
commit('SET_RUNES', data) commit('SET_RUNES', data)
}, },
} }
export const getters = { export const getters = {
runesLoaded: state => state.runes, runesLoaded: (state) => state.runes,
} }

View file

@ -4,17 +4,17 @@ import { axios } from '@/plugins/axios'
export const namespaced = true export const namespaced = true
export const state = { export const state = {
matches: [] matches: [],
} }
export const mutations = { export const mutations = {
MATCH_LOADING(state, matchId) { MATCH_LOADING(state, matchId) {
const alreadyIn = state.matches.find(m => m.matchId === matchId) const alreadyIn = state.matches.find((m) => m.matchId === matchId)
if (!alreadyIn) { if (!alreadyIn) {
state.matches.push({ matchId, status: 'loading' }) state.matches.push({ matchId, status: 'loading' })
} }
}, },
MATCH_FOUND(state, {matchDetails, ranksLoaded }) { MATCH_FOUND(state, { matchDetails, ranksLoaded }) {
matchDetails.status = 'loaded' matchDetails.status = 'loaded'
matchDetails.ranksLoaded = ranksLoaded matchDetails.ranksLoaded = ranksLoaded
@ -28,11 +28,11 @@ export const mutations = {
} }
} }
const index = state.matches.findIndex(m => m.matchId === matchDetails.matchId) const index = state.matches.findIndex((m) => m.matchId === matchDetails.matchId)
Vue.set(state.matches, index, matchDetails) Vue.set(state.matches, index, matchDetails)
}, },
MATCH_RANKS_FOUND(state, { matchId, ranksByPlayer }) { MATCH_RANKS_FOUND(state, { matchId, ranksByPlayer }) {
const match = state.matches.find(m => m.matchId === matchId) const match = state.matches.find((m) => m.matchId === matchId)
for (const player of match.blueTeam.players) { for (const player of match.blueTeam.players) {
const ranks = ranksByPlayer[player.id] const ranks = ranksByPlayer[player.id]
@ -43,7 +43,7 @@ export const mutations = {
for (const player of match.redTeam.players) { for (const player of match.redTeam.players) {
const ranks = ranksByPlayer[player.id] const ranks = ranksByPlayer[player.id]
if (!ranks) continue if (!ranks) continue
Vue.set(player, 'rank', ranks[420]) Vue.set(player, 'rank', ranks[420])
} }
match.ranksLoaded = true match.ranksLoaded = true
@ -55,23 +55,29 @@ export const actions = {
commit('MATCH_LOADING', matchId) commit('MATCH_LOADING', matchId)
console.log('MATCH DETAILS STORE', matchId) console.log('MATCH DETAILS STORE', matchId)
const resp = await axios(({ url: 'match/details', data: { matchId }, method: 'POST' })).catch(() => { }) const resp = await axios({ url: 'match/details', data: { matchId }, method: 'POST' }).catch(
() => {}
)
console.log('--- DETAILS INFOS ---') console.log('--- DETAILS INFOS ---')
console.log(resp.data) console.log(resp.data)
const {matchDetails, ranksLoaded} = resp.data const { matchDetails, ranksLoaded } = resp.data
commit('MATCH_FOUND', {matchDetails, ranksLoaded }) commit('MATCH_FOUND', { matchDetails, ranksLoaded })
// If the ranks of the players are not yet known // If the ranks of the players are not yet known
if (!ranksLoaded) { if (!ranksLoaded) {
const ranks = await axios(({ url: 'match/details/ranks', data: { matchId }, method: 'POST' })).catch(() => { }) const ranks = await axios({
url: 'match/details/ranks',
data: { matchId },
method: 'POST',
}).catch(() => {})
if (!ranks) return if (!ranks) return
console.log('--- RANK OF MATCH DETAILS ---') console.log('--- RANK OF MATCH DETAILS ---')
console.log(ranks.data) console.log(ranks.data)
commit('MATCH_RANKS_FOUND', { matchId, ranksByPlayer: ranks.data }) commit('MATCH_RANKS_FOUND', { matchId, ranksByPlayer: ranks.data })
} }
} },
} }
export const getters = { export const getters = {
getMatchDetails: state => matchId => state.matches.find(m => m.matchId === matchId), getMatchDetails: (state) => (matchId) => state.matches.find((m) => m.matchId === matchId),
} }

View file

@ -1,7 +1,7 @@
export const namespaced = true export const namespaced = true
export const state = { export const state = {
notifications: [] notifications: [],
} }
let nextId = 1 let nextId = 1
@ -10,14 +10,14 @@ export const mutations = {
PUSH(state, notification) { PUSH(state, notification) {
state.notifications.push({ state.notifications.push({
...notification, ...notification,
id: nextId++ id: nextId++,
}) })
}, },
DELETE(state, notificationToRemove) { DELETE(state, notificationToRemove) {
state.notifications = state.notifications.filter( state.notifications = state.notifications.filter(
notification => notification.id !== notificationToRemove.id (notification) => notification.id !== notificationToRemove.id
) )
} },
} }
export const actions = { export const actions = {
@ -26,5 +26,5 @@ export const actions = {
}, },
remove({ commit }, notificationToRemove) { remove({ commit }, notificationToRemove) {
commit('DELETE', notificationToRemove) commit('DELETE', notificationToRemove)
} },
} }

View file

@ -12,14 +12,18 @@ export const mutations = {
state.favorites.push(summoner) state.favorites.push(summoner)
}, },
ADD_SEARCH(state, summoner) { ADD_SEARCH(state, summoner) {
const alreadyFav = state.favorites.find(s => s.name === summoner.name && s.region === summoner.region) const alreadyFav = state.favorites.find(
(s) => s.name === summoner.name && s.region === summoner.region
)
if (alreadyFav) { if (alreadyFav) {
return return
} }
let searches = state.recentSearches let searches = state.recentSearches
const alreadySearch = searches.find(s => s.name === summoner.name && s.region === summoner.region) const alreadySearch = searches.find(
(s) => s.name === summoner.name && s.region === summoner.region
)
if (alreadySearch) { if (alreadySearch) {
alreadySearch.date = Date.now() alreadySearch.date = Date.now()
searches.sort((a, b) => b.date - a.date) searches.sort((a, b) => b.date - a.date)
@ -34,39 +38,59 @@ export const mutations = {
searches.unshift(summoner) searches.unshift(summoner)
}, },
REMOVE_FAVORITE(state, summoner) { REMOVE_FAVORITE(state, summoner) {
state.favorites = state.favorites.filter(s => s.name !== summoner.name || s.region !== summoner.region) state.favorites = state.favorites.filter(
(s) => s.name !== summoner.name || s.region !== summoner.region
)
}, },
REMOVE_SEARCH(state, summoner) { REMOVE_SEARCH(state, summoner) {
state.recentSearches = state.recentSearches.filter(s => s.name !== summoner.name || s.region !== summoner.region) state.recentSearches = state.recentSearches.filter(
(s) => s.name !== summoner.name || s.region !== summoner.region
)
}, },
UPDATE_SETTING(state, { name, value }) { UPDATE_SETTING(state, { name, value }) {
state[name] = value state[name] = value
} },
} }
export const actions = { export const actions = {
addRecentSearch({ commit, dispatch, state }, summoner) { addRecentSearch({ commit, dispatch, state }, summoner) {
commit('ADD_SEARCH', summoner) commit('ADD_SEARCH', summoner)
dispatch('updateSettings', { name: 'recentSearches', value: state.recentSearches, isJson: true }) dispatch('updateSettings', {
name: 'recentSearches',
value: state.recentSearches,
isJson: true,
})
}, },
removeRecentSearch({ commit, dispatch }, summoner) { removeRecentSearch({ commit, dispatch }, summoner) {
commit('REMOVE_SEARCH', summoner) commit('REMOVE_SEARCH', summoner)
dispatch('updateSettings', { name: 'recentSearches', value: state.recentSearches, isJson: true }) dispatch('updateSettings', {
name: 'recentSearches',
value: state.recentSearches,
isJson: true,
})
}, },
updateFavorite({ commit, dispatch, state }, summoner) { updateFavorite({ commit, dispatch, state }, summoner) {
const alreadyFav = state.favorites.find(s => s.name === summoner.name && s.region === summoner.region) const alreadyFav = state.favorites.find(
(s) => s.name === summoner.name && s.region === summoner.region
)
if (alreadyFav) { if (alreadyFav) {
commit('REMOVE_FAVORITE', summoner) commit('REMOVE_FAVORITE', summoner)
} else { } else {
if (state.favorites.length >= 6) { if (state.favorites.length >= 6) {
// Display error message // Display error message
return dispatch('notification/add', { return dispatch(
type: 'error', 'notification/add',
message: 'Too many favorite summoners.' {
}, { root: true }) type: 'error',
message: 'Too many favorite summoners.',
},
{ root: true }
)
} }
commit('ADD_FAVORITE', summoner) commit('ADD_FAVORITE', summoner)
const searched = state.recentSearches.find(s => s.name === summoner.name && s.region === summoner.region) const searched = state.recentSearches.find(
(s) => s.name === summoner.name && s.region === summoner.region
)
if (searched) { if (searched) {
dispatch('removeRecentSearch', summoner) dispatch('removeRecentSearch', summoner)
} }
@ -75,7 +99,7 @@ export const actions = {
dispatch('updateSettings', { name: 'favorites', value: state.favorites, isJson: true }) dispatch('updateSettings', { name: 'favorites', value: state.favorites, isJson: true })
}, },
updatePercent({ commit }, percent) { updatePercent({ commit }, percent) {
if (typeof (percent) !== 'boolean') { if (typeof percent !== 'boolean') {
percent = localStorage.getItem('settings-percent') === 'true' percent = localStorage.getItem('settings-percent') === 'true'
} else { } else {
localStorage.setItem('settings-percent', percent) localStorage.setItem('settings-percent', percent)
@ -91,5 +115,5 @@ export const actions = {
localStorage.setItem(name, isJson ? JSON.stringify(value) : value) localStorage.setItem(name, isJson ? JSON.stringify(value) : value)
} }
commit('UPDATE_SETTING', { name, value }) commit('UPDATE_SETTING', { name, value })
} },
} }

View file

@ -19,15 +19,15 @@ export const state = {
stats: {}, stats: {},
loaded: false, loaded: false,
matchesLoading: false, matchesLoading: false,
moreMatchesToFetch: true moreMatchesToFetch: true,
}, },
champions: { champions: {
list: [], list: [],
championsLoaded: false championsLoaded: false,
}, },
records: { records: {
list: {}, list: {},
recordsLoaded: false recordsLoaded: false,
}, },
live: { live: {
match: {}, match: {},
@ -124,12 +124,20 @@ export const actions = {
const regionId = rootState.regionsList[region] const regionId = rootState.regionsList[region]
commit('BASIC_REQUEST') commit('BASIC_REQUEST')
try { try {
const resp = await axios(({ url: 'summoner/basic', data: { summoner, region: regionId }, method: 'POST' })) const resp = await axios({
url: 'summoner/basic',
data: { summoner, region: regionId },
method: 'POST',
})
if (!resp.data) { if (!resp.data) {
dispatch('notification/add', { dispatch(
type: 'error', 'notification/add',
message: 'Summoner not found.' {
}, { root: true }) type: 'error',
message: 'Summoner not found.',
},
{ root: true }
)
return commit('SUMMONER_NOT_FOUND') return commit('SUMMONER_NOT_FOUND')
} }
@ -139,17 +147,25 @@ export const actions = {
commit('SUMMONER_FOUND', infos) commit('SUMMONER_FOUND', infos)
// Add summoner to recent searches // Add summoner to recent searches
dispatch('settings/addRecentSearch', { dispatch(
name: infos.account.name, 'settings/addRecentSearch',
icon: infos.account.profileIconId, {
region, name: infos.account.name,
}, { root: true }) icon: infos.account.profileIconId,
region,
},
{ root: true }
)
} catch (error) { } catch (error) {
if (error.response && error.response.status === 422) { if (error.response && error.response.status === 422) {
dispatch('notification/add', { dispatch(
type: 'error', 'notification/add',
message: 'Summoner not found.' {
}, { root: true }) type: 'error',
message: 'Summoner not found.',
},
{ root: true }
)
} }
if (error.message !== 'Summoner changed') { if (error.message !== 'Summoner changed') {
commit('SUMMONER_NOT_FOUND') commit('SUMMONER_NOT_FOUND')
@ -160,7 +176,11 @@ export const actions = {
commit('CHAMPIONS_NOT_FOUND') commit('CHAMPIONS_NOT_FOUND')
}, },
async championsRequest({ commit }, queue = null) { async championsRequest({ commit }, queue = null) {
const resp = await axios(({ url: 'summoner/champions', data: { puuid: state.basic.account.puuid, queue: queue }, method: 'POST' })).catch(() => { }) const resp = await axios({
url: 'summoner/champions',
data: { puuid: state.basic.account.puuid, queue: queue },
method: 'POST',
}).catch(() => {})
console.log('---CHAMPIONS---') console.log('---CHAMPIONS---')
console.log(resp.data) console.log(resp.data)
@ -168,14 +188,14 @@ export const actions = {
}, },
async liveMatchRequest({ commit, rootState }) { async liveMatchRequest({ commit, rootState }) {
commit('LIVE_LOADING') commit('LIVE_LOADING')
const resp = await axios(({ const resp = await axios({
url: 'summoner/live', url: 'summoner/live',
data: { data: {
id: state.basic.account.id, id: state.basic.account.id,
region: rootState.regionsList[rootState.settings.region] region: rootState.regionsList[rootState.settings.region],
}, },
method: 'POST' method: 'POST',
})).catch(() => { }) }).catch(() => {})
console.log('---LIVE---') console.log('---LIVE---')
console.log(resp.data) console.log(resp.data)
@ -191,37 +211,41 @@ export const actions = {
if (!state.overview.matches.length) return if (!state.overview.matches.length) return
const lastMatchId = state.overview.matches[state.overview.matches.length - 1].matchId const lastMatchId = state.overview.matches[state.overview.matches.length - 1].matchId
const resp = await axios(({ const resp = await axios({
url: 'match', url: 'match',
data: { data: {
puuid: state.basic.account.puuid, puuid: state.basic.account.puuid,
region: rootState.regionsList[rootState.settings.region], region: rootState.regionsList[rootState.settings.region],
lastMatchId lastMatchId,
}, },
method: 'POST' method: 'POST',
})).catch(() => { }) }).catch(() => {})
console.log('---MATCHES INFOS---') console.log('---MATCHES INFOS---')
console.log(resp.data) console.log(resp.data)
const newMatches = createMatchData(resp.data.matches) const newMatches = createMatchData(resp.data.matches)
commit('MATCHES_FOUND', { newMatches, stats: resp.data.stats }) commit('MATCHES_FOUND', { newMatches, stats: resp.data.stats })
}, },
async overviewRequest({ commit, rootState }) { async overviewRequest({ commit, rootState }) {
const resp = await axios(({ const resp = await axios({
url: 'summoner/overview', url: 'summoner/overview',
data: { data: {
puuid: state.basic.account.puuid, puuid: state.basic.account.puuid,
accountId: state.basic.account.accountId, accountId: state.basic.account.accountId,
region: rootState.regionsList[rootState.settings.region], region: rootState.regionsList[rootState.settings.region],
}, },
method: 'POST' method: 'POST',
})).catch(() => { }) }).catch(() => {})
console.log('---OVERVIEW---') console.log('---OVERVIEW---')
console.log(resp.data) console.log(resp.data)
resp.data.matches = createMatchData(resp.data.matchesDetails) resp.data.matches = createMatchData(resp.data.matchesDetails)
commit('OVERVIEW_FOUND', resp.data) commit('OVERVIEW_FOUND', resp.data)
}, },
async recordsRequest({ commit }) { async recordsRequest({ commit }) {
const resp = await axios(({ url: 'summoner/records', data: { puuid: state.basic.account.puuid }, method: 'POST' })).catch(() => { }) const resp = await axios({
url: 'summoner/records',
data: { puuid: state.basic.account.puuid },
method: 'POST',
}).catch(() => {})
console.log('---RECORDS---') console.log('---RECORDS---')
console.log(resp.data) console.log(resp.data)
const records = resp.data.length ? createRecordsData(resp.data) : {} const records = resp.data.length ? createRecordsData(resp.data) : {}
@ -233,15 +257,15 @@ export const actions = {
}, },
updateSeason({ commit }, season) { updateSeason({ commit }, season) {
commit('UPDATE_SEASON', { season }) commit('UPDATE_SEASON', { season })
} },
} }
export const getters = { export const getters = {
matchesLoading: state => state.overview.matchesLoading, matchesLoading: (state) => state.overview.matchesLoading,
overviewLoaded: state => state.overview.loaded, overviewLoaded: (state) => state.overview.loaded,
playing: state => state.live.playing, playing: (state) => state.live.playing,
regionFilterApplied: state => !!state.basic.currentSeason, regionFilterApplied: (state) => !!state.basic.currentSeason,
summonerFound: state => state.basic.status === 'found', summonerFound: (state) => state.basic.status === 'found',
summonerNotFound: state => state.basic.status === 'error', summonerNotFound: (state) => state.basic.status === 'error',
summonerLoading: state => state.basic.status === 'loading', summonerLoading: (state) => state.basic.status === 'loading',
} }

3
client/src/style.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -1,30 +1,32 @@
<template> <template>
<div class="relative overflow-hidden bg-blue-900"> <div class="relative overflow-hidden bg-blue-900">
<LazyBackground <LazyBackground
:image-source="require('@/assets/img/bg-homepage-1.jpg')" image-source="/img/bg-homepage-1.jpg"
image-class="absolute inset-0 bg-center" image-class="absolute inset-0 bg-center"
transition-name="fade" transition-name="fade"
></LazyBackground> ></LazyBackground>
<div class="flex flex-col items-center justify-center h-screen"> <div class="flex h-screen flex-col items-center justify-center">
<div class="absolute top-0 right-0"> <div class="absolute right-0 top-0">
<div class="relative w-20 h-2 mt-4 mr-4 line line-top"></div> <div class="line line-top relative mr-4 mt-4 h-2 w-20"></div>
</div> </div>
<div class="absolute bottom-0 left-0"> <div class="absolute bottom-0 left-0">
<div class="relative w-20 h-2 mb-4 ml-4 line line-bottom"></div> <div class="line line-bottom relative mb-4 ml-4 h-2 w-20"></div>
</div> </div>
<div class="relative flex flex-col items-center w-full max-w-lg"> <div class="relative flex w-full max-w-lg flex-col items-center">
<img class="absolute logo" src="@/assets/img/Logo.svg" alt="logo" /> <img class="logo absolute" src="/img/Logo.svg" alt="logo" />
<SearchForm @formSubmit="redirect" :homepage="true" /> <SearchForm @formSubmit="redirect" :homepage="true" />
</div> </div>
<p <p
class="absolute bottom-0 pb-4 leading-tight text-center text-blue-300 horizontal-center text-xxs" class="horizontal-center absolute bottom-0 pb-4 text-center text-xxs leading-tight text-blue-300"
> >
LeagueStats.gg isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot Games or anyone officially involved in producing or managing Riot Games properties. LeagueStats.gg isn't endorsed by Riot Games and doesn't reflect the views or opinions of
<br />Riot Games, and all associated properties are trademarks or registered trademarks of Riot Games, Inc. Riot Games or anyone officially involved in producing or managing Riot Games properties.
<br />Riot Games, and all associated properties are trademarks or registered trademarks of
Riot Games, Inc.
</p> </p>
</div> </div>
</div> </div>
@ -37,7 +39,7 @@ import SearchForm from '@/components/Form/SearchForm.vue'
export default { export default {
components: { components: {
LazyBackground, LazyBackground,
SearchForm SearchForm,
}, },
methods: { methods: {
@ -50,7 +52,7 @@ export default {
return { return {
title: 'LeagueStats.gg', title: 'LeagueStats.gg',
} }
} },
} }
</script> </script>
@ -60,7 +62,7 @@ export default {
} }
.line::after { .line::after {
content: ""; content: '';
position: absolute; position: absolute;
width: 4.5rem; width: 4.5rem;
height: 0.5rem; height: 0.5rem;

View file

@ -2,12 +2,12 @@
<div <div
v-if="overviewLoaded" v-if="overviewLoaded"
key="overview" key="overview"
class="relative flex items-start justify-between mt-3 text-center vue-sticky-container" class="vue-sticky-container relative mt-3 flex items-start justify-between text-center"
> >
<VueStickySidebar <VueStickySidebar
:top-spacing="48" :top-spacing="48"
:bottom-spacing="123" :bottom-spacing="123"
class="z-40 sidebar" class="sidebar z-40"
container-selector=".vue-sticky-container" container-selector=".vue-sticky-container"
> >
<SummonerChampions /> <SummonerChampions />
@ -32,11 +32,12 @@
@clicked="moreMatches" @clicked="moreMatches"
:loading="matchesLoading" :loading="matchesLoading"
btn-class="block px-4 py-2 mx-auto mt-4 font-semibold bg-blue-800 rounded-md shadow-lg hover:bg-blue-1000" btn-class="block px-4 py-2 mx-auto mt-4 font-semibold bg-blue-800 rounded-md shadow-lg hover:bg-blue-1000"
>More matches</LoadingButton> >More matches</LoadingButton
>
</div> </div>
<div v-else> <div v-else>
<div class="flex justify-center"> <div class="flex justify-center">
<div class="px-4 py-3 text-lg font-bold text-center text-blue-100 rounded-lg bg-gradient"> <div class="bg-gradient rounded-lg px-4 py-3 text-center text-lg font-bold text-blue-100">
<div>No matches found.</div> <div>No matches found.</div>
<div>😕</div> <div>😕</div>
</div> </div>
@ -49,7 +50,6 @@
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex' import { mapState, mapActions, mapGetters } from 'vuex'
import LiveMatch from '@/components/Match/LiveMatch.vue' import LiveMatch from '@/components/Match/LiveMatch.vue'
@ -70,15 +70,15 @@ export default {
SummonerChampions, SummonerChampions,
SummonerMates, SummonerMates,
SummonerStats, SummonerStats,
VueStickySidebar VueStickySidebar,
}, },
computed: { computed: {
...mapState({ ...mapState({
current: state => state.summoner.live.match, current: (state) => state.summoner.live.match,
overview: state => state.summoner.overview, overview: (state) => state.summoner.overview,
}), }),
...mapGetters('summoner', ['matchesLoading', 'overviewLoaded', 'summonerFound']) ...mapGetters('summoner', ['matchesLoading', 'overviewLoaded', 'summonerFound']),
}, },
watch: { watch: {
@ -87,7 +87,7 @@ export default {
}, },
summonerFound() { summonerFound() {
this.fetchData() this.fetchData()
} },
}, },
created() { created() {
@ -114,7 +114,7 @@ export default {
return { return {
title: 'Summoner Overview', title: 'Summoner Overview',
} }
} },
} }
</script> </script>

View file

@ -34,7 +34,7 @@ export default {
return { return {
onlyMostPlayed: false, onlyMostPlayed: false,
queue: null, queue: null,
searchChampions: '' searchChampions: '',
} }
}, },
@ -42,24 +42,24 @@ export default {
queues() { queues() {
// Only keep the gameModes the summoner has played // Only keep the gameModes the summoner has played
const queues = Object.keys(gameModes) const queues = Object.keys(gameModes)
.filter(gameMode => .filter(
gameModes[gameMode].type !== 'Bot' && (gameMode) =>
this.gamemodes.includes(Number(gameMode)) gameModes[gameMode].type !== 'Bot' && this.gamemodes.includes(Number(gameMode))
) )
.reduce((obj, key) => { .reduce((obj, key) => {
return { return {
...obj, ...obj,
[key]: gameModes[key] [key]: gameModes[key],
} }
}, {}) }, {})
return { '0': { type: 'Normal', name: 'All queues' }, ...queues } return { 0: { type: 'Normal', name: 'All queues' }, ...queues }
}, },
...mapGetters('summoner', ['summonerFound']), ...mapGetters('summoner', ['summonerFound']),
...mapState({ ...mapState({
champions: state => state.summoner.champions.list, champions: (state) => state.summoner.champions.list,
championsLoaded: state => state.summoner.champions.championsLoaded, championsLoaded: (state) => state.summoner.champions.championsLoaded,
gamemodes: state => state.summoner.basic.gamemodes gamemodes: (state) => state.summoner.basic.gamemodes,
}) }),
}, },
watch: { watch: {
@ -68,7 +68,7 @@ export default {
}, },
summonerFound() { summonerFound() {
this.fetchData() this.fetchData()
} },
}, },
created() { created() {
@ -96,6 +96,6 @@ export default {
return { return {
title: 'Summoner Champions', title: 'Summoner Champions',
} }
} },
} }
</script> </script>

View file

@ -1,14 +1,18 @@
<template> <template>
<div key="live-game"> <div key="live-game">
<div v-if="playing || summonerLoading"> <div v-if="playing || summonerLoading">
<div v-if="liveLoaded" class="flex items-center justify-end -mt-4 text-base text-blue-200"> <div v-if="liveLoaded" class="-mt-4 flex items-center justify-end text-base text-blue-200">
<div>{{ gamemode.type }} {{ gamemode.name }}</div> <div>{{ gamemode.type }} {{ gamemode.name }}</div>
<div class="mx-2">-</div> <div class="mx-2">-</div>
<div :class="{'w-12': displayStartTime !== 'Not started yet'}">{{ displayStartTime }}</div> <div :class="{ 'w-12': displayStartTime !== 'Not started yet' }">
{{ displayStartTime }}
</div>
<button <button
@click="liveMatchRequest" @click="liveMatchRequest"
class="px-3 py-1 ml-4 text-blue-100 bg-blue-800 rounded-md shadow-md hover:bg-blue-760" class="ml-4 rounded-md bg-blue-800 px-3 py-1 text-blue-100 shadow-md hover:bg-blue-760"
>Reload</button> >
Reload
</button>
</div> </div>
<div v-else class="h-4"></div> <div v-else class="h-4"></div>
@ -16,14 +20,16 @@
<LiveTeam :team="enemyTeam" :ally="false" :gamemode="gamemode.name" class="mt-4" /> <LiveTeam :team="enemyTeam" :ally="false" :gamemode="gamemode.name" class="mt-4" />
</div> </div>
<div v-else> <div v-else>
<div class="flex justify-center mt-16"> <div class="mt-16 flex justify-center">
<div class="px-4 py-3 text-lg font-bold text-center text-blue-100 rounded-lg bg-gradient"> <div class="bg-gradient rounded-lg px-4 py-3 text-center text-lg font-bold text-blue-100">
<div>This summoner is not in game.</div> <div>This summoner is not in game.</div>
<div class="mt-2">🕊</div> <div class="mt-2">🕊</div>
<button <button
@click="liveMatchRequest" @click="liveMatchRequest"
class="px-3 py-1 my-4 text-sm text-blue-100 bg-blue-800 rounded-md shadow-md hover:bg-blue-760" class="my-4 rounded-md bg-blue-800 px-3 py-1 text-sm text-blue-100 shadow-md hover:bg-blue-760"
>Reload</button> >
Reload
</button>
</div> </div>
</div> </div>
</div> </div>
@ -45,16 +51,16 @@ export default {
computed: { computed: {
...mapGetters('summoner', ['summonerLoading', 'summonerFound']), ...mapGetters('summoner', ['summonerLoading', 'summonerFound']),
...mapState({ ...mapState({
live: state => state.summoner.live.match, live: (state) => state.summoner.live.match,
liveLoaded: state => state.summoner.live.liveLoaded, liveLoaded: (state) => state.summoner.live.liveLoaded,
playing: state => state.summoner.live.playing, playing: (state) => state.summoner.live.playing,
}) }),
}, },
watch: { watch: {
summonerFound() { summonerFound() {
this.fetchData() this.fetchData()
} },
}, },
created() { created() {
@ -77,6 +83,6 @@ export default {
return { return {
title: 'Summoner Live Game', title: 'Summoner Live Game',
} }
} },
} }
</script> </script>

View file

@ -2,9 +2,11 @@
<div key="records"> <div key="records">
<template v-if="!recordsLoaded || (recordsLoaded && records.assists)"> <template v-if="!recordsLoaded || (recordsLoaded && records.assists)">
<div <div
class="relative pl-6 text-2xl text-blue-200 border-b-2 border-blue-800 category blue-900" class="category blue-900 relative border-b-2 border-blue-800 pl-6 text-2xl text-blue-200"
>Basics</div> >
<div class="flex flex-wrap -mx-2"> Basics
</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded"> <template v-if="recordsLoaded">
<RecordCard <RecordCard
color="#63b3ed" color="#63b3ed"
@ -53,7 +55,7 @@
<div <div
v-for="index in 6" v-for="index in 6"
:key="index" :key="index"
style="width: 176px; height: 294px;" style="width: 176px; height: 294px"
class="mx-2 mt-6" class="mx-2 mt-6"
> >
<content-loader <content-loader
@ -68,8 +70,12 @@
</div> </div>
</template> </template>
</div> </div>
<div class="relative pl-6 mt-3 text-2xl text-blue-200 border-b-2 border-blue-800 blue-900 category">Game impact</div> <div
<div class="flex flex-wrap -mx-2"> class="blue-900 category relative mt-3 border-b-2 border-blue-800 pl-6 text-2xl text-blue-200"
>
Game impact
</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded"> <template v-if="recordsLoaded">
<RecordCard <RecordCard
color="#FC8181" color="#FC8181"
@ -119,7 +125,7 @@
<div <div
v-for="index in 6" v-for="index in 6"
:key="index" :key="index"
style="width: 176px; height: 294px;" style="width: 176px; height: 294px"
class="mx-2 mt-6" class="mx-2 mt-6"
> >
<content-loader <content-loader
@ -134,8 +140,10 @@
</div> </div>
</template> </template>
</div> </div>
<div class="relative pl-6 mt-3 text-2xl text-blue-200 border-b-2 border-blue-800 category">Miscellaneous</div> <div class="category relative mt-3 border-b-2 border-blue-800 pl-6 text-2xl text-blue-200">
<div class="flex flex-wrap -mx-2"> Miscellaneous
</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded"> <template v-if="recordsLoaded">
<RecordCard <RecordCard
color="#4299E1" color="#4299E1"
@ -170,7 +178,7 @@
<div <div
v-for="index in 4" v-for="index in 4"
:key="index" :key="index"
style="width: 176px; height: 294px;" style="width: 176px; height: 294px"
class="mx-2 mt-6" class="mx-2 mt-6"
> >
<content-loader <content-loader
@ -185,8 +193,10 @@
</div> </div>
</template> </template>
</div> </div>
<div class="relative pl-6 mt-3 text-2xl text-blue-200 border-b-2 border-blue-800 category">Multi kills</div> <div class="category relative mt-3 border-b-2 border-blue-800 pl-6 text-2xl text-blue-200">
<div class="flex flex-wrap -mx-2"> Multi kills
</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded"> <template v-if="recordsLoaded">
<RecordCard <RecordCard
color="#FEFCBF" color="#FEFCBF"
@ -228,7 +238,7 @@
<div <div
v-for="index in 5" v-for="index in 5"
:key="index" :key="index"
style="width: 176px; height: 294px;" style="width: 176px; height: 294px"
class="mx-2 mt-6" class="mx-2 mt-6"
> >
<content-loader <content-loader
@ -245,7 +255,7 @@
</div> </div>
</template> </template>
<template v-if="recordsLoaded && !records.assists"> <template v-if="recordsLoaded && !records.assists">
<div class="flex flex-col items-center mt-4"> <div class="mt-4 flex flex-col items-center">
<div>No records have been found.</div> <div>No records have been found.</div>
<div>😕</div> <div>😕</div>
</div> </div>
@ -267,9 +277,9 @@ export default {
computed: { computed: {
...mapGetters('summoner', ['summonerFound']), ...mapGetters('summoner', ['summonerFound']),
...mapState({ ...mapState({
records: state => state.summoner.records.list, records: (state) => state.summoner.records.list,
recordsLoaded: state => state.summoner.records.recordsLoaded, recordsLoaded: (state) => state.summoner.records.recordsLoaded,
}) }),
}, },
watch: { watch: {
@ -278,7 +288,7 @@ export default {
}, },
summonerFound() { summonerFound() {
this.fetchData() this.fetchData()
} },
}, },
created() { created() {
@ -298,14 +308,14 @@ export default {
return { return {
title: 'Summoner Records', title: 'Summoner Records',
} }
} },
} }
</script> </script>
<style scoped> <style scoped>
.category:before { .category:before {
@apply w-2 h-2 bg-blue-200 absolute block left-0 ml-1; @apply absolute left-0 ml-1 block h-2 w-2 bg-blue-200;
content: ""; content: '';
top: 35%; top: 35%;
transform: rotate(45deg); transform: rotate(45deg);
} }

View file

@ -1,21 +1,38 @@
/* /*
** TailwindCSS Configuration File ** TailwindCSS Configuration File
** **
** Docs: https://tailwindcss.com/docs/configuration ** Docs: https://tailwindcss.com/docs/configuration
** Default: https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js ** Default: https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/config.full.js
*/ */
const defaultTheme = require('tailwindcss/defaultTheme') const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = { module.exports = {
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
theme: { theme: {
customForms: theme => ({ fontSize: {
'xxs': ['0.625rem'],
'xs': ['0.75rem'],
'sm': ['0.875rem'],
'base': ['1rem'],
'lg': ['1.125rem'],
'xl': ['1.25rem'],
'2xl': ['1.5rem'],
'3xl': ['1.875rem'],
'4xl': ['2.25rem'],
'5xl': ['3rem'],
'6xl': ['3.75rem'],
'7xl': ['4.5rem'],
'8xl': ['6rem'],
'9xl': ['8rem'],
},
customForms: (theme) => ({
default: { default: {
checkbox: { checkbox: {
width: theme('spacing.6'), 'width': theme('spacing.6'),
height: theme('spacing.6'), 'height': theme('spacing.6'),
backgroundColor: 'rgba(23, 49, 79, 0.6)', 'backgroundColor': 'rgba(23, 49, 79, 0.6)',
borderColor: theme('colors.blue.800'), 'borderColor': theme('colors.blue.800'),
textColor: theme('colors.blue.1000'), 'textColor': theme('colors.blue.1000'),
'&:focus': { '&:focus': {
backgroundColor: theme('colors.blue.1000'), backgroundColor: theme('colors.blue.1000'),
borderColor: theme('colors.blue.700'), borderColor: theme('colors.blue.700'),
@ -24,64 +41,47 @@ module.exports = {
'&:checked': { '&:checked': {
backgroundColor: theme('colors.blue.1000'), backgroundColor: theme('colors.blue.1000'),
borderColor: 'transparent', borderColor: 'transparent',
} },
} },
} },
}), }),
extend: { extend: {
colors: { colors: {
teal: { teal: {
...defaultTheme.colors.teal, 100: '#E6FFFA',
'flashy': '#24e8cc', 200: '#B2F5EA',
300: '#81E6D9',
400: '#4FD1C5',
500: '#38B2AC',
600: '#319795',
700: '#2C7A7B',
800: '#285E61',
900: '#234E52',
flashy: '#24e8cc',
}, },
blue: { blue: {
...defaultTheme.colors.blue, 100: '#EBF8FF',
200: '#BEE3F8',
300: '#90CDF4',
400: '#63B3ED',
500: '#4299E1',
600: '#3182CE',
700: '#2B6CB0',
800: '#2C5282',
900: '#2A4365',
760: '#2C5C94', 760: '#2C5C94',
850: '#2B4B74', 850: '#2B4B74',
1000: '#17314f' 1000: '#17314f',
}, },
}, },
spacing: {
'2px': '2px',
'3p5': '0.875rem',
'4b': '1.15rem',
'11': '2.75rem',
},
borderWidth: {
'3': '3px',
},
fontFamily: { fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans], sans: ['Inter', ...defaultTheme.fontFamily.sans],
}, },
fontSize: {
xxs: '0.625rem',
},
height: {
'200': '50rem',
'1/2': '50%',
},
maxWidth: {
'12': '3rem',
},
width: {
'22': '5.5rem',
},
}, },
}, },
variants: {
textColor: ['responsive', 'hover', 'focus', 'group-hover'],
},
plugins: [ plugins: [
require('@tailwindcss/custom-forms'), require('@tailwindcss/forms')({
strategy: 'class',
}),
], ],
purge: {
enabled: process.env.NODE_ENV === 'production',
content: [
'./src/**/*.vue',
'./public/**/*.html',
]
},
future: {
removeDeprecatedGapUtilities: true,
},
} }

18
client/vite.config.js Normal file
View file

@ -0,0 +1,18 @@
import path from 'path'
// import eslint from 'vite-plugin-eslint'
import vue from '@vitejs/plugin-vue2'
export default {
esbuild: {
drop: ['console', 'debugger'],
},
plugins: [vue()],
resolve: {
alias: {
'@/': `${path.resolve(__dirname, 'src')}/`,
},
},
server: {
port: 8080,
},
}

View file

@ -1,3 +0,0 @@
module.exports = {
productionSourceMap: false
}

View file

@ -1,5 +1,5 @@
{ {
"folders": [ "folders": [
{ {
"path": "client" "path": "client"
}, },
@ -7,18 +7,31 @@
"path": "server" "path": "server"
} }
], ],
"settings": { "settings": {
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.tabSize": 2, "editor.tabSize": 2,
"vetur.validation.style": false, "files.insertFinalNewline": true,
"headwind.prependCustomClasses": false, "[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}, },
"extensions": { "extensions": {
"recommendations": [ "recommendations": [
"octref.vetur", "vue.volar",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"stylelint.vscode-stylelint", "stylelint.vscode-stylelint",
"heybourn.headwind",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode"
] ]
} }
} }

View file

@ -54,7 +54,11 @@ export default class SummonersController {
// Add job in 1sec to load entire matchlist in DB (in background) // Add job in 1sec to load entire matchlist in DB (in background)
const matchListMode = summonerDB.$isLocal ? MatchListMode.FIRSTIME : MatchListMode.UPDATE const matchListMode = summonerDB.$isLocal ? MatchListMode.FIRSTIME : MatchListMode.UPDATE
Bull.schedule(new FetchMatchList().key, { puuid: account.puuid, region, matchListMode }, 1000) Bull.schedule(
new FetchMatchList().key,
{ puuid: account.puuid, region, mode: matchListMode },
1000
)
// All seasons the summoner has played // All seasons the summoner has played
finalJSON.seasons = await this.getSeasons(account.puuid) finalJSON.seasons = await this.getSeasons(account.puuid)

View file

@ -5,7 +5,7 @@
"scripts": { "scripts": {
"dev": "node ace serve --watch", "dev": "node ace serve --watch",
"build": "node ace build --production", "build": "node ace build --production",
"start": "node server.js", "start": "node build/server.js",
"lint": "eslint . --ext=.ts", "lint": "eslint . --ext=.ts",
"format": "prettier --write ." "format": "prettier --write ."
}, },