refactor: start the new summoner page design

This commit is contained in:
Valentin Kaelin 2019-09-14 23:19:10 +02:00
parent f48bfc92ec
commit d97accce23
16 changed files with 233 additions and 133 deletions

View file

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

View file

@ -1,56 +1,20 @@
@import url('https://fonts.googleapis.com/css?family=Lato:300,400,700,900'); @import url('https://fonts.googleapis.com/css?family=Lato:300,400,700,900');
.transition-all { button:focus {
transition-property: all; outline: 0;
} }
.transition-fastest { .vertical-center {
transition-duration: 50ms; top: 50%;
transform: translateY(-50%);
} }
.transition-faster { .horizontal-center {
transition-duration: 100ms; left: 0;
right: 0;
margin: 0 auto;
} }
.transition-fast { .bg-gradient {
transition-duration: 150ms; background: linear-gradient(180deg, #2C5282 0%, rgba(44, 82, 130, 0) 100%);
}
.transition-medium {
transition-duration: 200ms;
}
.ease-out-quad {
transition-timing-function: cubic-bezier(.25, .46, .45, .94);
}
.ease-in-quad {
transition-timing-function: cubic-bezier(.55, .085, .68, .53);
}
.scale-70 {
transform: scale(.7);
}
.scale-100 {
transform: scale(1);
}
.fade-enter-active, .fade-leave-active {
transition: opacity 2s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.4s;
}
.slide-fade-enter,
.slide-fade-leave-to {
transform: translateX(400px);
opacity: 0;
} }

View file

@ -1,25 +0,0 @@
button:focus {
outline: 0;
}
.vertical-center {
top: 50%;
transform: translateY(-50%);
}
.horizontal-center {
left: 0;
right: 0;
margin: 0 auto;
}
.input {
border: 4px solid rgba(129, 230, 217, .7);
background: rgba(40, 94, 97, .35);
}
.input:focus,
.btn:hover {
background: rgba(40, 94, 97, .75);
border-color: rgba(129, 230, 217, .9);
}

View file

@ -1,3 +1,3 @@
@import 'tailwind.css'; @import 'tailwind.css';
@import 'base.css'; @import 'base.css';
@import 'form.css'; @import 'transition.css';

View file

@ -0,0 +1,54 @@
.transition-all {
transition-property: all;
}
.transition-fastest {
transition-duration: 50ms;
}
.transition-faster {
transition-duration: 100ms;
}
.transition-fast {
transition-duration: 150ms;
}
.transition-medium {
transition-duration: 200ms;
}
.ease-out-quad {
transition-timing-function: cubic-bezier(.25, .46, .45, .94);
}
.ease-in-quad {
transition-timing-function: cubic-bezier(.55, .085, .68, .53);
}
.scale-70 {
transform: scale(.7);
}
.scale-100 {
transform: scale(1);
}
.fade-enter-active, .fade-leave-active {
transition: opacity 2s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.4s;
}
.slide-fade-enter,
.slide-fade-leave-to {
transform: translateX(400px);
opacity: 0;
}

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 672 KiB

After

Width:  |  Height:  |  Size: 672 KiB

View file

@ -26,6 +26,11 @@ export default {
required: false, required: false,
default: 'cover' default: 'cover'
}, },
moreBackgrounds: {
type: String,
required: false,
default: ''
},
transitionName: { transitionName: {
type: String, type: String,
required: false, required: false,
@ -43,7 +48,7 @@ export default {
computed: { computed: {
computedStyle () { computedStyle () {
if (this.imageState === 'loaded') { if (this.imageState === 'loaded') {
return 'background-image: url(' + this.asyncImage.src + '); background-size: ' + this.backgroundSize return `background-image: ${this.moreBackgrounds} url(${this.asyncImage.src}); background-size: ${this.backgroundSize}`
} }
return '' return ''
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<li class="match bg-white shadow text-sm md:text-base" :class="data.result ? 'win' : 'lose'"> <li class="match mt-4 bg-white shadow text-sm md:text-base" :class="data.result ? 'win' : 'lose'">
<div class="match-container"> <div class="match-container">
<!-- Responsive --> <!-- Responsive -->
<div <div
@ -91,7 +91,6 @@ export default {
<style scoped> <style scoped>
.match { .match {
border-bottom: 1px solid #dae1e7; border-bottom: 1px solid #dae1e7;
margin: 16px 0;
} }
.match .flex-container { .match .flex-container {

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="inline-block bg-blue-800 rounded-lg p-3"> <div class="inline-block bg-gradient rounded-lg p-3">
<h4 class="font-bold text-base text-white text-left">Recent Activity</h4> <h4 class="font-bold text-base text-white text-left">Recent Activity</h4>
<div class="flex"> <div class="flex">
<span class="ml-12 text-blue-200 font-semibold text-xs">{{ gridDays[0].month }}</span> <span class="ml-12 text-blue-200 font-semibold text-xs">{{ gridDays[0].month }}</span>

View file

@ -1,12 +1,13 @@
<template> <template>
<form @submit.prevent="formSubmit" class="flex text-teal-100 text-lg w-full"> <form @submit.prevent="formSubmit" :class="formClasses" class="flex text-teal-100 text-lg w-full">
<div v-if="dropdown" @click="dropdown = false" class="fixed z-20 inset-0"></div> <div v-if="dropdown" @click="dropdown = false" class="fixed z-20 inset-0"></div>
<div class="relative w-full"> <div class="relative w-full">
<input <input
v-model="summoner" v-model="summoner"
type="text" type="text"
autofocus autofocus
class="input w-full px-2 py-4 rounded-lg outline-none pl-8 pr-16 font-bold" :class="[elementClasses, inputClasses]"
class="input w-full px-2 rounded-lg outline-none pl-8 pr-16 font-bold"
/> />
<div class="absolute right-0 z-30 vertical-center flex items-center h-full mr-2"> <div class="absolute right-0 z-30 vertical-center flex items-center h-full mr-2">
<div <div
@ -49,7 +50,11 @@
</transition> </transition>
</div> </div>
<button class="input btn w-20 rounded-lg ml-2 relative" type="submit"> <button
:class="[elementClasses, btnClasses]"
class="input btn rounded-lg ml-2 relative"
type="submit"
>
<v-icon name="search" class="absolute vertical-center horizontal-center"></v-icon> <v-icon name="search" class="absolute vertical-center horizontal-center"></v-icon>
</button> </button>
</form> </form>
@ -57,6 +62,12 @@
<script> <script>
export default { export default {
props: {
size: {
type: String,
default: 'xl'
}
},
data() { data() {
return { return {
summoner: '', summoner: '',
@ -77,6 +88,31 @@ export default {
selectedRegion: 'EUW' selectedRegion: 'EUW'
} }
}, },
computed: {
btnClasses() {
return {
'w-12': this.size === 'small',
'w-20': this.size === 'xl'
}
},
elementClasses() {
return {
'border-2': this.size === 'small',
'border-4': this.size === 'xl'
}
},
formClasses() {
return {
'max-w-lg': this.size === 'small',
}
},
inputClasses() {
return {
'py-2': this.size === 'small',
'py-4': this.size === 'xl'
}
}
},
methods: { methods: {
classRegions(index) { classRegions(index) {
return { return {
@ -103,4 +139,15 @@ export default {
.offsetIcon { .offsetIcon {
left: 4px; left: 4px;
} }
.input {
border-color: rgba(129, 230, 217, .7);
background: rgba(40, 94, 97, .35);
}
.input:focus,
.btn:hover {
background: rgba(40, 94, 97, .75);
border-color: rgba(129, 230, 217, .9);
}
</style> </style>

View file

@ -17,11 +17,12 @@ export function createSummonerData(RiotData, championsInfos) {
const soloQ = soloQStats ? {} : null const soloQ = soloQStats ? {} : null
if (soloQ) { if (soloQ) {
soloQ.rank = soloQStats.rank soloQ.rank = `${soloQStats.tier} ${soloQStats.rank}`
soloQ.rankImgLink = getRankImg(soloQStats) soloQ.rankImgLink = getRankImg(soloQStats)
soloQ.wins = soloQStats.wins soloQ.wins = soloQStats.wins
soloQ.losses = soloQStats.losses soloQ.losses = soloQStats.losses
soloQ.winrate = (soloQ.wins * 100 / (soloQ.wins + soloQ.losses)).toFixed(1) + '%' soloQ.winrate = (soloQ.wins * 100 / (soloQ.wins + soloQ.losses)).toFixed(1) + '%'
soloQ.lp = soloQStats.leaguePoints
} }
const matchesInfos = [] const matchesInfos = []

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="bg-blue-900"> <div class="bg-blue-900">
<LazyBackground <LazyBackground
:image-source="require('@/assets/bg-homepage-1.jpg')" :image-source="require('@/assets/img/bg-homepage-1.jpg')"
image-class="absolute inset-0" image-class="absolute inset-0"
transition-name="fade" transition-name="fade"
></LazyBackground> ></LazyBackground>
@ -16,7 +16,7 @@
</div> </div>
<div class="relative flex flex-col items-center w-full max-w-lg"> <div class="relative flex flex-col items-center w-full max-w-lg">
<img class="absolute logo" src="@/assets/Logo.svg" alt="logo" /> <img class="absolute logo" src="@/assets/img/Logo.svg" alt="logo" />
<SearchForm @formSubmit="redirect" /> <SearchForm @formSubmit="redirect" />
</div> </div>
</div> </div>

View file

@ -1,75 +1,128 @@
<template> <template>
<div> <div class="bg-blue-900">
<header class="search mb-4 bg-teal-900 text-teal-100"> <LazyBackground
<div class="container mx-auto flex justify-between py-8"> :image-source="require('@/assets/img/bg-homepage-1.jpg')"
<router-link image-class="fixed w-full h-200 z-0"
to="/" more-backgrounds="linear-gradient(180deg, rgba(42, 67, 101, 0) 0%, #2A4365 50%),"
class="flex items-center text-lg text-teal-100 mr-8 hover:text-teal-200" transition-name="fade"
>Home</router-link> ></LazyBackground>
<SearchForm @formSubmit="redirect" /> <div class="relative z-10">
</div> <header class="mb-4 text-teal-100">
</header> <div class="container mx-auto flex justify-between items-center">
<router-link to="/">
<img class="w-56" src="@/assets/img/Logo.svg" alt="LeagueStats logo" />
</router-link>
<template v-if="summonerFound"> <SearchForm @formSubmit="redirect" size="small" />
<div class="container mx-auto pb-16"> </div>
<div class="mt-4 mx-auto p-4 text-center bg-blue-100 border border-gray-300 rounded-lg"> </header>
<div
class="mx-auto w-16 h-16 bg-gray-300"
:style="{background: `url(https://ddragon.leagueoflegends.com/cdn/${this.$patch}/img/profileicon/${summonerInfos.profileIconId}.png) center/cover`}"
></div>
<h1>{{ summonerInfos.name }}</h1>
<h3>{{ summonerInfos.level }}</h3>
<div v-if="summonerInfos.soloQ"> <template v-if="summonerFound">
<h3>{{ summonerInfos.rank }}</h3> <div class="container mx-auto text-white pb-12">
<div <div class="flex justify-between xl:px-12">
class="mx-auto w-16 h-16 bg-gray-300" <div>
:style="{background: `url(${summonerInfos.soloQ.rankImgLink}) center/cover`}" <h1 class="text-4xl font-extrabold uppercase">
></div> <span class="text-5xl">{{ summonerInfos.name[0] }}</span>
<h3>{{ `${summonerInfos.soloQ.wins} wins / ${summonerInfos.soloQ.losses} losses` }}</h3> <span>{{ summonerInfos.name.substring(1) }}</span>
<span>Winrate: {{ summonerInfos.soloQ.winrate }}</span> </h1>
<div class="flex">
<div>
<div
class="relative w-24 h-24 rounded-full bg-blue-1000 border-2 border-teal-400"
:style="{background: getSummonerIcon}"
>
<div
class="absolute left-0 bottom-0 w-8 h-8 flex items-center justify-center bg-blue-900 rounded-full text-xs text-teal-500 font-extrabold border-2 border-teal-400"
>{{ summonerInfos.level }}</div>
</div>
</div>
<div v-if="summonerInfos.soloQ" class="ml-6 leading-none">
<div class="text-lg font-extrabold">Solo/Duo</div>
<div
class="text-teal-500 text-4xl uppercase font-extrabold"
>{{ summonerInfos.soloQ.rank }}</div>
<div class="mt-4 flex items-start bg-gradient px-4 py-3 rounded-lg">
<div class="flex items-center">
<div
class="w-20 h-20 bg-blue-1000"
:style="{background: `url(${summonerInfos.soloQ.rankImgLink}) center/cover`}"
></div>
<div class="ml-2 text-xl font-extrabold">{{ summonerInfos.soloQ.lp }} LP</div>
</div>
<div class="ml-10 mt-2 font-extrabold uppercase leading-none">
<div class="text-teal-500 text-base">Record</div>
<div class="flex">
<div class="mt-2 text-sm leading-tight text-right">
<div>{{ summonerInfos.soloQ.wins }}</div>
<div>{{ summonerInfos.soloQ.losses }}</div>
</div>
<div class="ml-2 mt-2 text-sm leading-tight">
<div class="text-teal-500">Wins</div>
<div class="text-red-300">Losses</div>
</div>
</div>
</div>
<div class="ml-10 mt-2 font-extrabold">
<div class="text-teal-500 text-base uppercase">Winrate</div>
<div class="mt-2 text-xl leading-tight">{{ summonerInfos.soloQ.winrate }}</div>
</div>
</div>
</div>
</div>
</div>
<div>
<RecentActivity :matches="summonerInfos.allMatches" />
</div>
</div> </div>
<RecentActivity :matches="summonerInfos.allMatches" /> <div class="mt-12 text-center">
<ul class="text-gray-900">
<ul> <Match
<Match v-for="(match, index) in summonerInfos.matches"
v-for="(match, index) in summonerInfos.matches" :key="index"
:key="index" :data="summonerInfos.matches[index]"
:data="summonerInfos.matches[index]" />
/> </ul>
</ul> </div>
</div> </div>
</div> </template>
</template>
<template v-else-if="summonerLoading"> <template v-else-if="summonerLoading">
<div <div
class="flex items-center justify-center bg-white max-w-xs mx-auto p-5 rounded-lg shadow-xl" class="flex items-center justify-center bg-white max-w-xs mx-auto p-5 rounded-lg shadow-xl"
> >
<dot-loader :loading="summonerLoading" /> <dot-loader :loading="summonerLoading" />
</div> </div>
</template> </template>
<template v-else-if="summonerNotFound">
<p>Player can't be found.</p> <template v-else-if="summonerNotFound">
</template> <p>Player can't be found.</p>
</template>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex' import { mapState, mapActions, mapGetters } from 'vuex'
import LazyBackground from '@/components/LazyBackgroundImage.vue'
import RecentActivity from '@/components/RecentActivity.vue' import RecentActivity from '@/components/RecentActivity.vue'
import Match from '@/components/Match.vue' import Match from '@/components/Match.vue'
import SearchForm from '@/components/SearchForm.vue' import SearchForm from '@/components/SearchForm.vue'
export default { export default {
components: { components: {
LazyBackground,
Match, Match,
RecentActivity, RecentActivity,
SearchForm SearchForm
}, },
computed: { computed: {
getSummonerIcon() {
return `url(https://ddragon.leagueoflegends.com/cdn/${this.$patch}/img/profileicon/${this.summonerInfos.profileIconId}.png) center/cover`
},
summoner() { summoner() {
return this.$route.params.name return this.$route.params.name
}, },

View file

@ -85,6 +85,7 @@ module.exports = {
700: '#2b6cb0', 700: '#2b6cb0',
800: '#2c5282', 800: '#2c5282',
900: '#2a4365', 900: '#2a4365',
1000: '#17314f'
}, },
indigo: { indigo: {
100: '#ebf4ff', 100: '#ebf4ff',
@ -280,6 +281,7 @@ module.exports = {
...theme('spacing'), ...theme('spacing'),
full: '100%', full: '100%',
screen: '100vh', screen: '100vh',
'200': '50rem'
}), }),
minWidth: { minWidth: {
'0': '0', '0': '0',