Game page improvements

This commit is contained in:
Gamebrary 2022-12-03 00:26:48 -07:00
parent 4cb8a62ae4
commit f9e65418b7
11 changed files with 184 additions and 156 deletions

BIN
public/no-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -106,6 +106,7 @@ export default {
border-radius: .25rem;
}
}
.mw-empty-elt {
display: none;
}

View file

@ -1,16 +1,9 @@
<template>
<b-card
:img-src="gameHeaderImage"
img-alt="Image"
img-top
class="small mt-3"
bg-variant="light"
text-variant="dark"
>
<div>
<game-progress />
<div v-if="gameGenres" class="pr-2 pb-2">
<strong>Genres: </strong>
<div v-if="gameGenres">
<h4 class="mt-4">Genres: </h4>
<b-link
v-for="(genre, index) in gameGenres"
@ -21,8 +14,8 @@
</b-link>
</div>
<div v-if="gameModes" class="pr-2 pb-2">
<strong>{{ $t('board.gameModal.gameModes') }}: </strong>
<div v-if="gameModes">
<h4 class="mt-4">{{ $t('board.gameModal.gameModes') }}: </h4>
<b-link
v-for="(gameMode, index) in gameModes"
@ -33,8 +26,8 @@
</b-link>
</div>
<div v-if="playerPerspectives" class="pr-2 pb-2">
<strong>{{ $t('board.gameModal.perspective') }}: </strong>
<div v-if="playerPerspectives">
<h4 class="mt-4">{{ $t('board.gameModal.perspective') }}: </h4>
<b-link
v-for="({ id, name }, index) in playerPerspectives"
@ -46,8 +39,8 @@
</div>
<!-- TODO: restore release dates -->
<!-- <div class="pr-2 pb-2">
<strong>{{ $t('board.gameModal.releaseDate') }}</strong>
<!-- <div>
<h4 class="mt-4">{{ $t('board.gameModal.releaseDate') }}</h4>
<ol v-if="releaseDates" class="list-unstyled mb-0">
<li
v-for="{ id, platform, date } in releaseDates"
@ -62,8 +55,8 @@
</div>
</div> -->
<div v-if="user" class="pr-2 pb-2">
<strong>Found in: </strong>
<div v-if="user">
<h4 class="mt-4">Found in: </h4>
<b-link v-if="!boardsWithGame.length" v-b-modal.addRemoveGameModal>
Add to list
@ -81,15 +74,13 @@
<add-remove-game />
</div>
<div v-if="user" class="pr-2 pb-2">
<strong>Tags: </strong>
<div v-if="user">
<h4 class="mt-4">Tags: </h4>
<b-link v-if="!tagsApplied.length" v-b-modal.gameTagsModal>
Add tag
</b-link>
<br />
<b-button
v-for="({ bgColor, textColor, name, index }) in tagsApplied"
:key="index"
@ -107,8 +98,7 @@
<game-tags-modal />
</div>
<strong>Other links</strong>
<br>
<h4 class="mt-4">Other links</h4>
<b-button
v-for="{ url, id, icon, svg } in gameLinks"
@ -134,16 +124,13 @@
/>
</b-button>
<b-button
<b-link
v-if="officialWebsiteUrl"
class="mt-3"
v-b-modal.officialWebsite
block
:title="officialWebsiteUrl"
variant="secondary"
>
Official website
</b-button>
</b-link>
<b-modal
id="officialWebsite"
@ -171,7 +158,7 @@
/>
</b-modal>
</b-card>
</div>
</template>
<script>
@ -202,9 +189,10 @@ export default {
return this.boards?.filter(({ lists }) => lists?.some(({ games }) => games?.includes(this.game?.id))) || [];
},
gameHeaderImage() {
return this.game?.steam?.header_image;
},
// TODO: find a good use for game header image
// gameHeaderImage() {
// return this.game?.steam?.header_image;
// },
officialWebsiteUrl() {
return this.gameLinks?.find(({ id }) => id === 'official')?.url;

View file

@ -1,11 +1,13 @@
<template lang="html">
<div class="mt-3">
<b-row no-gutters>
<div
<b-form-row>
<b-col
v-for="({ imageUrl, isVideo, isCover }, index) in gameMedia"
cols="6"
sm="4"
:key="index"
>
<div class="mr-2 align-items-center text-center mb-2 rounded cursor-pointer position-relative">
<div class="align-items-center text-center mb-2 rounded cursor-pointer">
<i
v-if="isVideo"
class="fa-solid fa-play video-indicator position-absolute text-white"
@ -21,12 +23,14 @@
<b-img
:src="imageUrl"
rounded
style="height: 180px"
class="mb-2"
fluid
style="max-height: 120px;"
@click="viewMedia(index)"
/>
</div>
</div>
</b-row>
</b-col>
</b-form-row>
<b-modal
id="mediaModal"

View file

@ -1,7 +1,7 @@
<!-- TODO: hide progress if game is not yet released -->
<template lang="html">
<div class="pr-2 pb-2">
<strong>Progress: </strong>
<div>
<h4 class="mt-4">Progress: </h4>
<b-link @click="editing = true">{{ progress }}%</b-link>
<b-form v-if="editing">
@ -96,6 +96,3 @@ export default {
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
</style>

View file

@ -1,6 +1,6 @@
<template lang="html">
<section v-if="similarGames.length" class="my-5 bg-light p-3">
<h4 class="text-center mb-3">You may also like</h4>
<section v-if="similarGames.length" :class="['my-5 px-3 py-5', hasWallpaper ? '' : 'bg-light']">
<h4 :class="['text-center mb-3', { 'text-outlined': hasWallpaper }]">You may also like</h4>
<div class="similar-games">
<router-link
@ -27,6 +27,10 @@ import { getImageUrl } from '@/utils';
export default {
getImageUrl,
props: {
hasWallpaper: Boolean,
},
data() {
return {
similarGames: [],

View file

@ -1,12 +1,19 @@
<template lang="html">
<b-card
v-if="game"
:img-src="$options.getImageUrl(game)"
:img-src="gameCoverUrl"
:img-alt="game.name"
:class="['mb-3 cursor-pointer', { 'border-selected': selected }]"
overlay
@click="handleClick"
>
<strong
v-if="noImage"
class="text-center pb-5 d-flex justify-content-center"
>
{{ game.name }}
</strong>
<div v-if="selected" class="selected-indicator rounded bg-success text-white">
<i class="fa fa-check" />
</div>
@ -16,11 +23,10 @@
<script>
import { getImageUrl } from '@/utils';
import { mapState } from 'vuex';
import { NO_IMAGE_PATH } from '@/constants';
import slugify from 'slugify'
export default {
getImageUrl,
props: {
game: {
type: Object,
@ -37,10 +43,18 @@ export default {
return this.boards.find(({ id }) => id === boardId);
},
gameCoverUrl() {
return getImageUrl(this.game);
},
selected() {
return this.selectedList?.games?.includes(this.game.id)
},
noImage() {
return NO_IMAGE_PATH === this.gameCoverUrl;
},
selectedList() {
const { listIndex } = this.$route.query;

View file

@ -74,6 +74,7 @@ export default {
},
isBoardPage() {
// TODO: do show blurred background in game page
return ['board', 'game'].includes(this.$route.name);
},
},

View file

@ -15,6 +15,7 @@ export const MAX_PROFILE_LENGTH = 20;
export const STEAM_CATEGORY_ID = 13;
export const GOG_CATEGORY_ID = 17;
export const TWITTER_CATEGORY_ID = 5;
export const NO_IMAGE_PATH = '/no-image.png';
export const LIST_VIEW_SINGLE = 'single';
export const LIST_VIEW_COVERS = 'covers';

View file

@ -16,7 +16,13 @@
<b-spinner v-if="loading" class="spinner-centered" />
<template v-else-if="game">
<div v-if="backdrop" class="backdrop" :style="`background-image: url('${backdrop.url}')`" />
<div
v-if="backdrop"
class="backdrop"
:style="`background-image: url('${backdrop.url}')`"
v-b-modal.mediaModal
/>
<b-container>
<portal to="pageTitle">
@ -99,123 +105,135 @@
<b-col
cols="12"
md="8"
xl="9"
lg="5"
xl="6"
:class="['pt-3', darkTheme || hasWallpaper ? 'text-light' : '']"
>
<article :class="darkTheme || hasWallpaper ? 'text-light' : ''">
<div class="d-flex justify-content-between" v-b-visible="visibleHandler">
<h2 :class="{ 'mt-3': backdrop }">{{ game.name }}</h2>
</div>
<div class="d-flex justify-content-between" v-b-visible="visibleHandler">
<h2 :class="{ 'mt-3': backdrop }">{{ game.name }}</h2>
</div>
<game-description />
<game-description />
<b-alert
v-if="note"
v-html="note"
show
class="cursor-pointer mt-3"
variant="warning"
@click.native="$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug } })"
/>
<div v-if="gameDevelopers.length" class="mt-3">
<h4>Developed by:</h4>
<b-link
v-for="developer in gameDevelopers"
:key="developer.id"
:to="{ name: 'company', params: { id: developer.id }}"
>
<b-img
v-if="developer.logo"
:src="$options.getImageUrl(developer)"
:alt="developer.name"
width="120"
/>
<!-- <b-link v-if="!boardsWithGame.length" v-b-modal.addRemoveGameModal>
Add to list
</b-link> -->
<span v-else>{{ developer.name }}</span>
</b-link>
</div>
<div v-if="gamePublishers.length" class="mt-3">
<h4>Published by:</h4>
<b-link
v-for="publisher in gamePublishers"
:key="publisher.id"
:to="{ name: 'company', params: { id: publisher.id }}"
>
<!-- TODO: use publisher.logo.alpha_channel to style logo -->
<b-img
v-if="publisher.logo"
:src="$options.getImageUrl(publisher)"
:alt="publisher.name"
width="120"
/>
<span v-else>{{ publisher.name }}</span>
</b-link>
</div>
<b-alert
v-if="note"
v-html="note"
show
class="cursor-pointer mt-3"
variant="warning"
@click.native="$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug } })"
/>
<div class="mt-3" v-if="alternativeNames.length">
<p>Alternative names:</p>
<div
class="mb-1 small"
variant="light"
v-for="{ comment, id, name, imgUrl } in alternativeNames"
:key="id"
>
<b-avatar
v-b-tooltip.hover
:title="comment || null"
size="sm"
class="mr-1"
:src="imgUrl"
/>
{{ name }}
</div>
</div>
<div v-if="gamePlatforms">
<h4>Available for:</h4>
<b-link
v-for="platform in gamePlatforms"
:key="platform.id"
:to="{ name: 'search', query: { platforms: platform.id }}"
>
<b-img
v-if="platform.platform_logo"
:src="$options.getImageUrl(platform.platform_logo)"
:alt="platform.name"
thumbnail
width="100"
/>
<div v-else>
{{ platform.name }}
</div>
</b-link>
</div>
<!-- <b-link v-if="!boardsWithGame.length" v-b-modal.addRemoveGameModal>
Add to list
</b-link> -->
<game-ratings />
<game-details />
</article>
<game-ratings />
<small
v-if="legalNotice"
class="text-muted"
v-html="legalNotice"
/>
<game-media />
</b-col>
<b-col
cols="12"
md="12"
lg="3"
xl="3"
class="pt-3"
>
<game-details />
<div v-if="gamePublishers.length" class="d-flex justify-content-center flex-column">
<h4 class="mt-4">Published by:</h4>
<b-link
v-for="publisher in gamePublishers"
:key="publisher.id"
:to="{ name: 'company', params: { id: publisher.id }}"
>
<!-- TODO: use publisher.logo.alpha_channel to style logo -->
<b-img
v-if="publisher.logo"
:src="$options.getImageUrl(publisher)"
:alt="publisher.name"
width="120"
/>
<span v-else>{{ publisher.name }}</span>
</b-link>
</div>
<div v-if="gameDevelopers.length">
<h4 class="mt-4">Developed by:</h4>
<b-link
v-for="developer in gameDevelopers"
:key="developer.id"
:to="{ name: 'company', params: { id: developer.id }}"
>
<b-img
v-if="developer.logo"
:src="$options.getImageUrl(developer)"
:alt="developer.name"
width="120"
/>
<span v-else>{{ developer.name }}</span>
</b-link>
</div>
<div v-if="alternativeNames.length">
<h4 class="mt-4">Alternative names:</h4>
<div
class="mb-1"
variant="light"
v-for="{ comment, id, name, imgUrl } in alternativeNames"
:key="id"
>
<b-avatar
v-b-tooltip.hover
:title="comment || null"
size="sm"
class="mr-1"
:src="imgUrl"
/>
{{ name }}
</div>
</div>
<div v-if="gamePlatforms">
<h4 class="mt-4">Available for:</h4>
<b-button
v-for="platform in gamePlatforms"
:key="platform.id"
variant="transparent"
class="pb-0"
:to="{ name: 'search', query: { platforms: platform.id }}"
>
<b-img
v-if="platform.platform_logo"
:src="$options.getImageUrl(platform.platform_logo)"
:alt="platform.name"
class="mr-2 mb-2"
width="100"
/>
<b-avatar size="100" rounded v-else>
<small>{{ platform.name }}</small>
</b-avatar>
</b-button>
</div>
</b-col>
</b-row>
<game-media />
<section v-if="boardsWithGame.length" class="mt-3">
<strong :class="{ 'text-outlined': hasWallpaper }">Found in: </strong>
@ -246,7 +264,7 @@
</timeline> -->
</b-container>
<similar-games />
<similar-games :has-wallpaper="hasWallpaper" />
</template>
<div class="pt-5" v-else>

View file

@ -1,4 +1,4 @@
import { THUMBNAIL_PREFIX, IMAGE_SIZE_COVER_BIG } from '@/constants';
import { THUMBNAIL_PREFIX, IMAGE_SIZE_COVER_BIG, NO_IMAGE_PATH } from '@/constants';
export const bytesToSize = (bytes) => {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
@ -15,7 +15,7 @@ export const getImageUrl = (item, size = IMAGE_SIZE_COVER_BIG) => {
return imageId
? `https://images.igdb.com/igdb/image/upload/${size}/${imageId}.png`
: '/placeholder.gif';
: NO_IMAGE_PATH;
};
export const getFileExtension = (fileName) => {