mirror of
https://github.com/romancm/gamebrary
synced 2024-11-27 13:40:48 +00:00
Added loading placeholders
This commit is contained in:
parent
1bcd18715a
commit
dd0936c272
8 changed files with 1072 additions and 1063 deletions
88
src/components/GameBoard/GameBoardPlaceholder.vue
Normal file
88
src/components/GameBoard/GameBoardPlaceholder.vue
Normal file
|
@ -0,0 +1,88 @@
|
|||
<template lang="html">
|
||||
<div class="gameboard-placeholder">
|
||||
<div class="list" v-for="list in lists" :key="list.name">
|
||||
<div class="list-header" />
|
||||
|
||||
<div class="games">
|
||||
<div class="game">
|
||||
<placeholder
|
||||
image
|
||||
v-for="n in list.games.length"
|
||||
:lines="2"
|
||||
:key="n"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import Placeholder from '@/components/Placeholder/Placeholder';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Placeholder,
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['gameLists', 'platform']),
|
||||
|
||||
lists() {
|
||||
return this.gameLists && this.gameLists[this.platform.code]
|
||||
? this.gameLists[this.platform.code]
|
||||
: null;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
randomColumn() {
|
||||
return Math.floor(Math.random() * 4) + 1;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||
@import "~styles/styles.scss";
|
||||
|
||||
.gameboard-placeholder {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.list {
|
||||
flex-shrink: 0;
|
||||
cursor: default;
|
||||
border-radius: $border-radius;
|
||||
background: $color-white;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: $list-width;
|
||||
margin-right: $gp;
|
||||
max-height: calc(100vh - 81px);
|
||||
|
||||
.list-header {
|
||||
background: $color-dark-gray;
|
||||
height: $list-header-height;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.games {
|
||||
margin-top: $list-header-height;
|
||||
width: 100%;
|
||||
padding: $gp / 2;
|
||||
|
||||
.game {
|
||||
.placeholder {
|
||||
padding-right: $gp;
|
||||
background: $color-white;
|
||||
margin-bottom: $gp / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
110
src/components/GameDetail/GameDetailPlaceholder.vue
Normal file
110
src/components/GameDetail/GameDetailPlaceholder.vue
Normal file
|
@ -0,0 +1,110 @@
|
|||
<template lang="html">
|
||||
<div>
|
||||
<div class="game-detail">
|
||||
<div class="game-hero" />
|
||||
|
||||
<div class="game-detail-container">
|
||||
<div class="game-info">
|
||||
<placeholder image large />
|
||||
|
||||
<div>
|
||||
<placeholder :lines="1" large class="title" />
|
||||
<placeholder :lines="5" class="description" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Placeholder from '@/components/Placeholder/Placeholder';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Placeholder,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||
@import "~styles/styles.scss";
|
||||
|
||||
.game-detail {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: $color-light-gray;
|
||||
min-height: calc(100vh - #{$navHeight});
|
||||
|
||||
@media($small) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
.game-detail-container {
|
||||
background: #333;
|
||||
color: $color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.game-hero {
|
||||
background-color: $color-dark-gray;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
height: 400px;
|
||||
z-index: 1;
|
||||
|
||||
@media($small) {
|
||||
background: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.game-info {
|
||||
display: grid;
|
||||
grid-template-columns: 180px auto;
|
||||
grid-gap: $gp * 2;
|
||||
margin: 0 $gp;
|
||||
|
||||
@media($small) {
|
||||
grid-gap: 0;
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
|
||||
.game-description {
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
|
||||
.game-description {
|
||||
line-height: 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.game-detail-container {
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
-webkit-box-shadow: 0 0 2px 0 $color-gray;
|
||||
box-shadow: 0 0 2px 0 $color-gray;
|
||||
width: $container-width;
|
||||
max-width: 100%;
|
||||
z-index: 1;
|
||||
margin: 100px;
|
||||
padding: $gp 0;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.title {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.description {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
@media($small) {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
86
src/components/Placeholder/Placeholder.vue
Normal file
86
src/components/Placeholder/Placeholder.vue
Normal file
|
@ -0,0 +1,86 @@
|
|||
<template lang="html">
|
||||
<div class="placeholder" :class="{ 'has-image': image, large }" v-if="image || lines">
|
||||
<div class="image" v-if="image" />
|
||||
|
||||
<div class="text" v-if="lines">
|
||||
<div
|
||||
class="text-line"
|
||||
v-for="n in lines"
|
||||
:key="n"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
image: Boolean,
|
||||
large: Boolean,
|
||||
lines: Number,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||
@import "~styles/styles.scss";
|
||||
|
||||
.placeholder {
|
||||
max-width: 100%;
|
||||
|
||||
&.has-image {
|
||||
display: grid;
|
||||
grid-template-columns: 80px auto;
|
||||
grid-gap: $gp;
|
||||
}
|
||||
}
|
||||
|
||||
// Animation
|
||||
@keyframes placeholder{
|
||||
0%{
|
||||
background-position: -468px 0
|
||||
}
|
||||
100%{
|
||||
background-position: 468px 0
|
||||
}
|
||||
}
|
||||
|
||||
.animated-background {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: placeholder;
|
||||
animation-timing-function: linear;
|
||||
background: $color-light-gray;
|
||||
background: linear-gradient(to right,
|
||||
$color-light-gray 8%,
|
||||
#F0F0F0 18%, $color-light-gray 33%);
|
||||
background-size: 800px 104px;
|
||||
height: 96px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 120px;
|
||||
width: 80px;
|
||||
@extend .animated-background;
|
||||
}
|
||||
|
||||
.text-line {
|
||||
height: 12px;
|
||||
width: 100%;
|
||||
margin-bottom: $gp / 2;
|
||||
@extend .animated-background;
|
||||
}
|
||||
|
||||
.large {
|
||||
.text-line {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 220px;
|
||||
width: 175px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -7,14 +7,7 @@
|
|||
:class="{ dark: darkModeEnabled, 'drag-scroll-active': dragScrollActive }"
|
||||
v-dragscroll:nochilddrag
|
||||
>
|
||||
<template v-if="loading">
|
||||
Loading...
|
||||
</template>
|
||||
|
||||
<!-- <div v-else-if="!gameLists[platform.code]">
|
||||
// TODO: SHOW FTU
|
||||
Boom
|
||||
</div> -->
|
||||
<game-board-placeholder v-if="loading" />
|
||||
|
||||
<template>
|
||||
<list
|
||||
|
@ -22,7 +15,7 @@
|
|||
:games="list.games"
|
||||
:listIndex="listIndex"
|
||||
:key="`${list.name}-${listIndex}`"
|
||||
v-if="list"
|
||||
v-if="list && !loading"
|
||||
v-for="(list, listIndex) in gameLists[platform.code]"
|
||||
@end="dragEnd"
|
||||
@remove="tryDelete(listIndex)"
|
||||
|
@ -39,6 +32,7 @@
|
|||
<script>
|
||||
import { dragscroll } from 'vue-dragscroll';
|
||||
import AddList from '@/components/Lists/AddList';
|
||||
import GameBoardPlaceholder from '@/components/GameBoard/GameBoardPlaceholder';
|
||||
import Panel from '@/components/Panel/Panel';
|
||||
import { $success, $error, swal } from '@/shared/modals';
|
||||
import List from '@/components/GameBoard/List';
|
||||
|
@ -58,6 +52,7 @@ export default {
|
|||
draggable,
|
||||
List,
|
||||
AddList,
|
||||
GameBoardPlaceholder,
|
||||
Panel,
|
||||
},
|
||||
|
||||
|
@ -210,7 +205,7 @@ export default {
|
|||
|
||||
.panel {
|
||||
margin-right: $gp;
|
||||
width: 300px;
|
||||
width: $list-width;
|
||||
}
|
||||
|
||||
.lists {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<template lang="html">
|
||||
<!-- eslint-disable -->
|
||||
<div class="game-detail" v-if="game" :class="{ dark: darkModeEnabled }">
|
||||
<div>
|
||||
<game-detail-placeholder v-if="!game" />
|
||||
|
||||
<div class="game-detail" v-else :class="{ dark: darkModeEnabled }">
|
||||
<div class="game-hero" :style="style" />
|
||||
|
||||
<div class="game-detail-container">
|
||||
|
@ -45,6 +48,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -55,6 +59,7 @@ import GameScreenshots from '@/components/GameDetail/GameScreenshots';
|
|||
import GameVideos from '@/components/GameDetail/GameVideos';
|
||||
import GameReviewBox from '@/components/GameDetail/GameReviewBox';
|
||||
import AffiliateLink from '@/components/GameDetail/AffiliateLink';
|
||||
import GameDetailPlaceholder from '@/components/GameDetail/GameDetailPlaceholder';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -63,6 +68,7 @@ export default {
|
|||
GameVideos,
|
||||
GameReviewBox,
|
||||
AffiliateLink,
|
||||
GameDetailPlaceholder,
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template lang="html">
|
||||
<main v-dragscroll:nochilddrag>
|
||||
<span v-if="loading">Loading...</span>
|
||||
<game-board-placeholder v-if="loading" />
|
||||
|
||||
<section
|
||||
v-if="!loading && listData && publicGameData"
|
||||
|
@ -9,11 +9,9 @@
|
|||
>
|
||||
<header>{{ list.name }} ({{ list.games.length }})</header>
|
||||
|
||||
<div class="empty-list" v-if="!list.games.length">
|
||||
<h3>This collection is empty</h3>
|
||||
</div>
|
||||
<div class="games">
|
||||
<p v-if="!list.games.length">This list is empty</p>
|
||||
|
||||
<div class="games" v-else>
|
||||
<div
|
||||
v-if="publicGameData[game]"
|
||||
class="game-card"
|
||||
|
@ -35,6 +33,7 @@
|
|||
|
||||
<script>
|
||||
import firebase from 'firebase/app';
|
||||
import GameBoardPlaceholder from '@/components/GameBoard/GameBoardPlaceholder';
|
||||
import { swal } from '@/shared/modals';
|
||||
import { dragscroll } from 'vue-dragscroll';
|
||||
import { mapState } from 'vuex';
|
||||
|
@ -48,6 +47,10 @@ db.settings({
|
|||
});
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GameBoardPlaceholder,
|
||||
},
|
||||
|
||||
directives: {
|
||||
dragscroll,
|
||||
},
|
||||
|
|
|
@ -3,6 +3,7 @@ $gp: 16px;
|
|||
$navHeight: 48px;
|
||||
$container-width: 900px;
|
||||
$list-header-height: 30px;
|
||||
$list-width: 300px;
|
||||
|
||||
// Media queries
|
||||
$small: "max-width: 780px";
|
||||
|
|
Loading…
Reference in a new issue