speedruns.com, steam, and gog barebones integration

This commit is contained in:
Gamebrary 2022-02-25 18:49:00 -07:00
parent a86001be96
commit 8ede73779a
135 changed files with 1003 additions and 424 deletions

View file

@ -18,7 +18,7 @@ admin.initializeApp({
exports.steam = require('./steam');
exports.customSearch = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', "*");
res.set('Access-Control-Allow-Origin', '*');
if (!req.query.token) {
return res.status(400).json({ error: 'missing searchText or token' });
@ -53,13 +53,13 @@ exports.customSearch = functions.https.onRequest((req, res) => {
${limit}
${query}`;
axios({
return axios({
url: 'https://api.igdb.com/v4/games',
method: 'POST',
headers: {
'Accept': 'application/json',
Accept: 'application/json',
'Client-ID': functions.config().twitch.clientid,
'Authorization': `Bearer ${req.query.token}`,
Authorization: `Bearer ${req.query.token}`,
},
data,
})
@ -309,3 +309,22 @@ exports.email = functions.https.onRequest((req, res) => {
.then(({ data }) => { res.status(200).send(data) })
.catch((error) => { res.send(error) });
});
// https://gogapidocs.readthedocs.io/en/latest/listing.html
exports.gog = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', '*');
const { search } = req.query;
if (!search) return res.status(400).send('Missing search param');
axios({
url: `https://embed.gog.com/games/ajax/filtered?mediaType=game&search=${search}`,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch(error => res.send(error));
});

View file

@ -3,8 +3,27 @@ const axios = require('axios');
// const BASE_URL =
// TODO: put base url in constant
exports.game = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', '*');
const { gameId } = req.query;
if (!gameId) res.status(400).send('Missing steam gameId');
axios({
url: `https://store.steampowered.com/api/appdetails?appids=${gameId}`,
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch(error => res.send(error));
});
exports.news = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Origin', '*');
const { appId } = req.query;
if (!appId) res.send(400);
@ -14,15 +33,15 @@ exports.news = functions.https.onRequest((req, res) => {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch((error) => res.send(error));
.catch(error => res.send(error));
});
exports.friends = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Origin', '*');
const { appId } = req.query;
if (!appId) res.send(400);
@ -32,15 +51,15 @@ exports.friends = functions.https.onRequest((req, res) => {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch((error) => res.send(error));
.catch(error => res.send(error));
});
exports.ownedGames = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Origin', '*');
const { appId } = req.query;
if (!appId) res.send(400);
@ -50,15 +69,15 @@ exports.ownedGames = functions.https.onRequest((req, res) => {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch((error) => res.send(error));
.catch(error => res.send(error));
});
exports.gameList = functions.https.onRequest((req, res) => {
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Origin', '*');
const { appId } = req.query;
if (!appId) res.send(400);
@ -68,9 +87,9 @@ exports.gameList = functions.https.onRequest((req, res) => {
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
Accept: 'application/json',
},
})
.then(({ data }) => res.status(200).send(data))
.catch((error) => res.send(error));
.catch(error => res.send(error));
});

View file

@ -22,6 +22,7 @@
<title>Gamebrary</title>
<script src="https://kit.fontawesome.com/4c930ed66a.js" crossorigin="anonymous" />
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8" />
<script>
if (window.location.origin.indexOf('localhost') === -1) {
window['_fs_debug'] = false;

View file

@ -46,6 +46,7 @@
"vue-raven": "^1.0.0",
"vue-router": "^3.0.1",
"vue-shortkey": "^3.1.7",
"vue-tweet-embed": "^2.4.0",
"vuedraggable": "^2.24.3",
"vuefire": "^1.4.5",
"vuex": "^3.0.1",

View file

@ -15,8 +15,12 @@
v-shortkey="KEYBOARD_SHORTCUTS"
@shortkey="handleShortcutAction"
>
<dock v-if="user" />
<public-dock v-else />
<page-header />
<aside>
<dock v-if="user" />
<public-dock v-else />
</aside>
<main :class="{
'authorizing': !user,
@ -32,6 +36,7 @@
<script>
import Dock from '@/components/Dock';
import PublicDock from '@/components/PublicDock';
import PageHeader from '@/components/PageHeader';
import GlobalModals from '@/components/GlobalModals';
import sessionMixin from '@/mixins/sessionMixin';
import firebase from 'firebase/app';
@ -46,6 +51,7 @@ export default {
components: {
Dock,
PublicDock,
PageHeader,
GlobalModals,
},
@ -102,6 +108,8 @@ export default {
},
init() {
this.$store.dispatch('LOAD_IGDB_PLATFORMS');
if (this.isPublicRoute) {
return;
}
@ -130,47 +138,62 @@ export default {
</style>
<style lang="scss" rel="stylesheet/scss" scoped>
main {
overflow-y: auto;
height: calc(100vh - 54px);
&.authorizing {
height: 100vh;
width: 100%;
left: 0;
}
&.is-board {
height: 100vh;
}
}
.dock-left,
.dock-right {
#app {
height: 100vh;
display: grid;
grid-template-columns: 66px auto;
height: 100vh;
main {
height: 100vh;
}
grid-template-rows: 46px 1fr;
grid-template-columns: 65px 1fr;
}
.dock-right {
grid-template-columns: auto 66px;
main {
grid-row: 1;
}
header {
grid-column: 1/-1;
}
.dock-bottom {
display: flex;
flex-direction: column-reverse;
main {
justify-content: flex-end;
}
main {
overflow-y: auto;
border-radius: .5rem 0 0 0;
height: calc(100vh - 46px);
}
// main {
//
// &.authorizing {
// height: 100vh;
// width: 100%;
// left: 0;
// }
//
// &.is-board {
// height: 100vh;
// }
// }
//
// .dock-left,
// .dock-right {
// height: 100vh;
// display: grid;
// grid-template-columns: 66px auto;
// height: 100vh;
//
// main {
// height: 100vh;
// }
// }
//
// .dock-right {
// grid-template-columns: auto 66px;
//
// main {
// grid-row: 1;
// }
// }
//
// .dock-bottom {
// display: flex;
// flex-direction: column-reverse;
//
// main {
// justify-content: flex-end;
// }
// }
</style>

View file

@ -1,36 +1,26 @@
<template lang="html">
<div>
<template v-if="pinnedBoards.length">
<!-- v-for="{ id, name, backgroundColor, backgroundUrl } in pinnedBoards" -->
<b-button
v-for="{ id, name } in pinnedBoards"
v-for="{ id, name, backgroundColor, backgroundUrl } in pinnedBoards"
:key="id"
block
:title="name"
:variant="board.name === name ? 'warning' : null"
:class="['mb-1 p-0 cursor-pointer pinned-board', { active: board.name === name }]"
:style="`
${backgroundColor ? `background-color: ${backgroundColor};` : '' }
${getWallpaperUrl(backgroundUrl)}
`"
:class="['mb-1 pinned-board', { active: board.name === name }]"
@click="viewBoard(id)"
>
<!-- <b-avatar
rounded
:style="`
${backgroundColor ? `background-color: ${backgroundColor};` : null }
${getWallpaperUrl(backgroundUrl)}
`"
>
<span class="board-initials text-uppercase"></span>
</b-avatar> -->
<!-- {{ backgroundColor }} -->
<!-- <pre>{{ backgroundUrl }}</pre> -->
{{ getBoardInitials(name) }}
<span class="board-initials text-uppercase">{{ getBoardInitials(name) }}</span>
</b-button>
<hr class="mb-2 mt-0">
</template>
<template v-if="isBoard && !board.pinned">
<b-avatar
rounded
<b-button
class="active pinned-board"
:title="board.name"
:style="`
@ -42,7 +32,7 @@
<span class="board-initials text-uppercase mr-1">
{{ getBoardInitials(board.name) }}
</span>
</b-avatar>
</b-button>
<hr class="my-1">
</template>
@ -72,13 +62,8 @@ export default {
methods: {
getWallpaperUrl(url) {
if (!url) {
return '';
}
if (url && url.includes('igdb.com')) {
return `background-image: url(${url});`;
}
if (!url) return '';
if (url && url.includes('igdb.com')) return `background-image: url(${url});`;
const wallpaperObject = this.wallpapers.find(({ fullPath }) => fullPath === url);
@ -88,10 +73,10 @@ export default {
},
viewBoard(id) {
if (this.board.id !== id) {
this.$router.push({ name: 'board', params: { id } });
} else {
if (this.$route.name === 'board' && this.board.id === id) {
this.$bvModal.show('edit-board');
} else {
this.$router.push({ name: 'board', params: { id } });
}
},
@ -113,7 +98,7 @@ export default {
background-size: cover;
&.active {
box-shadow: inset 0 0 0 2px black;
box-shadow: inset 0 0 0 2px yellow;
}
}

View file

@ -43,6 +43,7 @@
:key="platform.id"
@click="handleClick(platform.id)"
>
<!-- <pre>{{ platform }}</pre> -->
<b-img
:src="`/static/logos/platforms/${platform.slug}.${platform.logoFormat}`"
:alt="platform.name"

View file

@ -1,38 +1,28 @@
<template lang="html">
<nav class="d-flex flex-column text-center dock p-2">
<b-button
title="Dashboard"
class="mb-2"
@click="handleLogoClick"
>
<!-- <img
src="/static/gamebrary-logo-dark.png"
width="32"
/> -->
<i class="fas fa-home" />
<!-- TODO: move back button to here when viewing a game that's part of a board -->
</b-button>
<nav class="d-flex flex-column text-center dock px-2">
<home-button class="mb-2 d-block d-sm-none" />
<pinned-boards />
<user-menu />
<b-button :to="{ name: 'settings' }" class="mb-2">
<b-button :to="{ name: 'settings' }" class="d-block d-sm-none mb-2">
<i class="fas fa-cog" />
</b-button>
<global-search />
<global-search class="d-block d-sm-none" />
</nav>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
import PinnedBoards from '@/components/Board/PinnedBoards';
import HomeButton from '@/components/Shared/HomeButton';
import GlobalSearch from '@/components/GlobalSearch';
import UserMenu from '@/components/UserMenu';
export default {
components: {
PinnedBoards,
HomeButton,
GlobalSearch,
UserMenu,
},
@ -55,20 +45,6 @@ export default {
},
methods: {
handleLogoClick() {
if (!this.user) {
if (this.$route.name === 'public-boards') {
this.$bvModal.show('authModal');
} else {
this.$router.push({ name: 'public-boards' });
}
}
if (this.user && this.$route.name !== 'home') {
this.$router.push({ name: 'home' });
}
},
// async pinBoard() {
// const payload = {
// ...this.board,

View file

@ -1,4 +1,5 @@
<!-- TODO: add speedruns -->
<!-- TODO: use v-observe-visibility -->
<template lang="html">
<div class="game">
<aside>
@ -8,6 +9,7 @@
:alt="game.name"
class="cursor-pointer game-cover"
fluid-grow
rounded
@click.stop="openGameCover"
/>
@ -31,10 +33,23 @@
<!-- <pre>{{ game.genres.map(({ id }) => id) }}</pre> -->
<!-- TODO: add bundles to game detail? -->
<!-- {{ game.bundles ? `Found in ${game.bundles.length} compilations.` : null }} -->
<timeline id="hellogames" sourceType="profile">
loading...
</timeline>
</aside>
<article>
<h3 class="mb-2">{{ game.name }}</h3>
<portal to="pageTitle">{{ game.name }}</portal>
<h3 class="mb-2">
{{ game.name }}
<b-badge variant="success" v-if="steamGame && steamGame.metacritic">{{ steamGame.metacritic.score }}</b-badge>
</h3>
<small v-if="gog && gog.isPriceVisible">{{gog.price.symbol}}{{ gog.price.amount }}</small>
<small><pre class="text-dark">{{ gog }}</pre></small>
<!-- <pre class="small text-dark">{{ steamGame }}</pre> -->
<b-progress
v-if="progress"
:value="progress"
@ -43,8 +58,9 @@
v-b-modal.progress
class="my-1 w-25"
/>
<game-description :game="game" />
<game-news :game="game" />
<game-description :game="game" :steam-game="steamGame" />
<game-platforms :game="game" />
<!-- <game-news :game="game" /> -->
<game-details :game="game" />
<game-websites
@ -96,8 +112,9 @@
<script>
import GameNotes from '@/components/Game/GameNotes';
import GameNews from '@/components/Game/GameNews';
// import GameNews from '@/components/Game/GameNews';
import GameDetails from '@/components/Game/GameDetails';
import GamePlatforms from '@/components/Game/GamePlatforms';
import GameRating from '@/components/Game/GameRating';
import GameDescription from '@/components/Game/GameDescription';
import SimilarGames from '@/components/Game/SimilarGames';
@ -105,15 +122,18 @@ import GameWebsites from '@/components/Game/GameWebsites';
import GameImages from '@/components/Game/GameImages';
import GameVideos from '@/components/Game/GameVideos';
import { mapGetters, mapState } from 'vuex';
import { Timeline } from 'vue-tweet-embed'
export default {
components: {
Timeline,
GameDescription,
GameDetails,
GamePlatforms,
GameRating,
GameImages,
GameNotes,
GameNews,
// GameNews,
GameVideos,
GameWebsites,
SimilarGames,
@ -124,6 +144,8 @@ export default {
type: Object,
required: true,
},
gog: Object,
steamGame: Object,
loading: Boolean,
},
@ -146,6 +168,12 @@ export default {
},
},
beforeDestroy() {
if (!['game', 'board'].includes(this.$route.name)) {
this.$store.commit('CLEAR_BOARD');
}
},
methods: {
openGameCover() {
this.$refs.gameImages.openModal();
@ -162,11 +190,11 @@ export default {
grid-gap: 1rem;
@media(max-width: 1280px) {
grid-template-columns: 360px auto;
grid-template-columns: 360px 1fr;
}
@media(max-width: 1024px) {
grid-template-columns: 320px auto;
grid-template-columns: 320px 1fr;
}
@media(max-width: 768px) {

View file

@ -22,6 +22,7 @@
Read more
</b-button>
<!-- <template v-if="!trimmedDescription">
<div
v-html="gameDescription"
@ -68,6 +69,7 @@ import { mapGetters } from 'vuex';
export default {
props: {
game: Object,
steamGame: Object,
},
data() {
@ -87,6 +89,10 @@ export default {
},
gameDescription() {
const steamDescription = this.steamGame && this.steamGame.short_description
? this.steamGame.short_description
: null;
const wikipediaDescription = this.wikipediaArticle && this.wikipediaArticle.extract
? this.wikipediaArticle.extract
: null;
@ -95,8 +101,7 @@ export default {
? this.game.summary
: null;
// Default to wikipedia, fall back to igdb
return wikipediaDescription || igdbDescription;
return steamDescription || wikipediaDescription || igdbDescription;
},
trimmedDescription() {
@ -106,6 +111,10 @@ export default {
},
source() {
if (this.steamGame && this.steamGame.short_description) {
return 'Steam';
}
return this.wikipediaArticle && this.wikipediaArticle.extract
? 'Wikipedia'
: 'IGDB';

View file

@ -1,67 +1,69 @@
<template lang="html">
<b-alert show variant="secondary" class="game-details">
<div v-if="game.alternative_names">
<strong>Also known as:</strong>
<div
class="mb-1"
rounded
v-for="alternativeName in game.alternative_names"
:key="alternativeName.id"
>
<b-avatar
v-b-tooltip.hover
:title="alternativeName.comment || null"
size="sm"
:src="`/static/img/country-flags/${getCountryCode(alternativeName.comment)}.svg`"
/>
<div>
<b-alert show variant="secondary" class="game-details">
<div v-if="game.alternative_names">
<strong>Also known as:</strong>
<div
class="mb-1"
rounded
v-for="alternativeName in game.alternative_names"
:key="alternativeName.id"
>
<b-avatar
v-b-tooltip.hover
:title="alternativeName.comment || null"
size="sm"
:src="`/static/img/country-flags/${getCountryCode(alternativeName.comment)}.svg`"
/>
{{ alternativeName.name }}
{{ alternativeName.name }}
</div>
</div>
</div>
<div v-if="platforms">
<strong>{{ $t('board.gameModal.platforms') }}:</strong>
<span class="text-wrap">{{ platforms }}</span>
</div>
<div v-if="platforms">
<strong>{{ $t('board.gameModal.platforms') }}:</strong>
<span class="text-wrap">{{ platforms }}</span>
</div>
<div v-if="genres">
<strong>{{ $t('board.gameModal.genres') }}:</strong>
<span class="text-wrap">{{ genres }}</span>
</div>
<div v-if="genres">
<strong>{{ $t('board.gameModal.genres') }}:</strong>
<span class="text-wrap">{{ genres }}</span>
</div>
<div v-if="gameModes">
<strong>{{ $t('board.gameModal.gameModes') }}:</strong>
<span class="text-wrap">{{ gameModes }}</span>
</div>
<div v-if="gameModes">
<strong>{{ $t('board.gameModal.gameModes') }}:</strong>
<span class="text-wrap">{{ gameModes }}</span>
</div>
<div v-if="gameDevelopers">
<strong>{{ $t('board.gameModal.developers') }}:</strong>
<span class="text-wrap">{{ gameDevelopers }}</span>
</div>
<div v-if="gameDevelopers">
<strong>{{ $t('board.gameModal.developers') }}:</strong>
<span class="text-wrap">{{ gameDevelopers }}</span>
</div>
<div v-if="gamePublishers">
<strong>{{ $t('board.gameModal.publishers') }}:</strong>
<span class="text-wrap">{{ gamePublishers }}</span>
</div>
<div v-if="gamePublishers">
<strong>{{ $t('board.gameModal.publishers') }}:</strong>
<span class="text-wrap">{{ gamePublishers }}</span>
</div>
<div v-if="playerPerspectives">
<strong>{{ $t('board.gameModal.perspective') }}:</strong>
<span class="text-wrap">{{ playerPerspectives }}</span>
</div>
<div v-if="playerPerspectives">
<strong>{{ $t('board.gameModal.perspective') }}:</strong>
<span class="text-wrap">{{ playerPerspectives }}</span>
</div>
{{ $t('board.gameModal.releaseDate') }}
{{ $t('board.gameModal.releaseDate') }}
<ul class="timeline">
<li
class="event pb-2"
:data-date="releaseDate.date"
:key="releaseDate.id"
v-for="releaseDate in timeline"
>
{{ releaseDate.platform }}
</li>
</ul>
</b-alert>
<ul class="timeline">
<li
class="event pb-2"
:data-date="releaseDate.date"
:key="releaseDate.id"
v-for="releaseDate in timeline"
>
{{ releaseDate.platform }}
</li>
</ul>
</b-alert>
</div>
</template>
<script>
@ -176,114 +178,3 @@ export default {
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.game-details {
font-size: small;
}
.timeline {
border-left: 3px solid #727cf5;
border-bottom-right-radius: 4px;
border-top-right-radius: 4px;
background: rgba(114, 124, 245, 0.09);
margin: 0 auto;
letter-spacing: 0.2px;
position: relative;
line-height: 1.4em;
font-size: 1.03em;
padding: 50px;
list-style: none;
text-align: left;
max-width: 40%;
}
@media (max-width: 767px) {
.timeline {
max-width: 98%;
padding: 25px;
}
}
.timeline .event {
// border-bottom: 1px dashed #e8ebf1;
// padding-bottom: 25px;
// margin-bottom: 25px;
position: relative;
}
@media (max-width: 767px) {
.timeline .event {
padding-top: 30px;
}
}
.timeline .event:last-of-type {
padding-bottom: 0;
margin-bottom: 0;
border: none;
}
.timeline .event:before,
.timeline .event:after {
position: absolute;
display: block;
top: 0;
}
.timeline .event:before {
left: -207px;
content: attr(data-date);
text-align: right;
font-weight: 100;
font-size: 0.9em;
min-width: 120px;
}
@media (max-width: 767px) {
.timeline .event:before {
left: 0px;
text-align: left;
}
}
.timeline .event:after {
-webkit-box-shadow: 0 0 0 3px #727cf5;
box-shadow: 0 0 0 3px #727cf5;
left: -55.8px;
background: #fff;
border-radius: 50%;
height: 9px;
width: 9px;
content: "";
top: 5px;
}
@media (max-width: 767px) {
.timeline .event:after {
left: -31.8px;
}
}
.rtl .timeline {
border-left: 0;
text-align: right;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 4px;
border-top-left-radius: 4px;
border-right: 3px solid #727cf5;
}
.rtl .timeline .event::before {
left: 0;
right: -170px;
}
.rtl .timeline .event::after {
left: 0;
right: -55.8px;
}
</style>

View file

@ -183,6 +183,7 @@ export default {
},
openModal(index = 0) {
console.log('open');
this.activeIndex = index;
this.$bvModal.show('game-images');

View file

@ -0,0 +1,118 @@
<template lang="html">
<div>
<!-- <pre>{{ game.platforms }}</pre> -->
<!-- <b-card>
<b-img
src="/static/logos/platforms-test/switch.png"
width="200"
/>
</b-card> -->
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
props: {
game: Object,
},
computed: {
...mapGetters(['platformNames']),
platforms() {
return this.game && this.game.platforms
? this.game.platforms.map(({ name }) => name).join(', ')
: null;
},
gameDevelopers() {
return this.game && this.game.involved_companies
? this.game.involved_companies
.filter(({ developer }) => developer)
.map(({ company }) => company.name).join(', ')
: null;
},
gamePublishers() {
return this.game && this.game.involved_companies
? this.game.involved_companies
.filter(({ publisher }) => publisher)
.map(({ company }) => company.name).join(', ')
: null;
},
gameModes() {
return this.game && this.game.game_modes
? this.game.game_modes.map(({ name }) => name).join(', ')
: null;
},
playerPerspectives() {
return this.game && this.game.player_perspectives
? this.game.player_perspectives.map(({ name }) => name).join(', ')
: null;
},
timeline() {
const releaseDates = this.game && this.game.release_dates;
const sortedActivities = releaseDates
? releaseDates.sort((a, b) => b.date - a.date)
: [];
return sortedActivities.length ? sortedActivities.map(releaseDate => ({
...releaseDate,
platform: this.platformNames[releaseDate.platform] ? this.platformNames[releaseDate.platform].name : null,
date: releaseDate.date ? this.$dayjs.unix(releaseDate.date).format('MMMM D, YYYY') : 'N/A',
}))
: null;
},
releaseDates() {
const hasReleaseDates = this.game && this.game.release_dates;
if (!hasReleaseDates) {
return 'N/A';
}
const formattedReleaseDates = this.game.release_dates.map(({ platform, date }) => {
const formattedDate = date
? this.$dayjs.unix(date).format('MMMM D, YYYY')
: 'N/A';
return this.platformNames[platform]
? `${this.platformNames[platform].name}: ${formattedDate}`
: null;
});
return [...new Set(formattedReleaseDates)];
},
},
methods: {
getCountryCode(alternateTitleDescription) {
if (!alternateTitleDescription) return 'un';
const description = alternateTitleDescription.toLowerCase();
if (description.includes('japanese')) return 'jp';
if (description.includes('korean')) return 'kr';
if (description.includes('portuguese')) return 'pt';
if (description.includes('brazilian')) return 'br';
if (description.includes('spanish')) return 'es';
if (description.includes('french')) return 'fr';
if (description.includes('italian')) return 'it';
if (description.includes('arabic')) return 'sa';
if (description.includes('polish')) return 'pl';
if (description.includes('russian')) return 'ru';
if (description.includes('chinese')) return 'cn';
if (description.includes('german')) return 'de';
if (description.includes('dutch')) return 'nl';
if (description.includes('european')) return 'eu';
return 'un';
},
},
};
</script>

View file

@ -1,6 +1,6 @@
<template lang="html">
<section class="d-flex align-items-end">
<pre class="bg-white text-dark ml-4 position-fixed text-small">{{ gameAgeRatings }}</pre>
<!-- <pre class="bg-white text-dark ml-4 position-fixed text-small">{{ gameAgeRatings }}</pre> -->
<!-- <pre class="bg-white text-dark ml-4 position-fixed text-small">{{ game.age_ratings }}</pre> -->
<!-- TODO: add CERO images -->
<!-- TODO: add USK images -->
@ -8,7 +8,7 @@
<!-- TODO: add CLASS_IND images -->
<!-- TODO: add ACB images -->
<!-- TODO: hook up settings -->
<img
<!-- <img
v-for="rating in gameAgeRatings"
:src="`/static/img/age-ratings/${rating.rating}`"
:alt="rating.name"
@ -16,7 +16,7 @@
v-b-tooltip.hover
:title="rating.name"
class="ml-2 rating"
/>
/> -->
<!-- <pre class="text-dark">
{{ ratings }}

View file

@ -1,32 +1,30 @@
<template lang="html">
<div v-if="game.websites" class="mt-4 d-block bg-danger">
<div :class="['links', { grid }]">
<b-button
v-for="{ url, id, icon, svg } in links"
:href="url"
:key="id"
:title="$t(`board.gameModal.links.${id}`)"
v-b-tooltip.hover
variant="transparent"
target="_blank"
class="text-left p-1 m-0"
>
<i
v-if="icon"
:class="`${icon} fa-fw`"
aria-hidden
/>
<div v-if="game.websites" class="mt-4 d-block">
<b-button
v-for="{ url, id, icon, svg } in links"
:href="url"
:key="id"
:title="$t(`board.gameModal.links.${id}`)"
v-b-tooltip.hover
variant="transparent"
target="_blank"
class="text-left p-1 m-0"
>
<i
v-if="icon"
:class="`${icon} fa-fw`"
aria-hidden
/>
<b-img
v-else-if="svg"
width="24"
class="mr-1"
:src="`/static/logos/companies/${id}.svg`"
/>
<b-img
v-else-if="svg"
width="24"
class="mr-1"
:src="`/static/logos/companies/${id}.svg`"
/>
<!-- <small>{{ $t(`board.gameModal.links.${id}`) }}</small> -->
</b-button>
</div>
<!-- <small>{{ $t(`board.gameModal.links.${id}`) }}</small> -->
</b-button>
</div>
</template>
@ -36,7 +34,6 @@ import { LINKS_CATEGORIES } from '@/constants';
export default {
props: {
game: Object,
grid: Boolean,
},
computed: {
@ -53,17 +50,3 @@ export default {
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.links {
// display: grid;
// grid-template-columns: 1fr 1fr 1fr;
// grid-gap: 5px;
&.grid {
// grid-template-columns: 1fr 1fr 1fr;
}
// @media(max-width: 780px) {
// }
}
</style>

View file

@ -1,7 +1,7 @@
<template lang="html">
<b-card
no-body
bg-variant="light"
bg-variant="transparent"
class="card clickable"
>
<b-row

View file

@ -1,6 +1,6 @@
<template lang="html">
<div class="global-search">
<b-button v-b-toggle.global-search block>
<b-button v-b-toggle.global-search block size="sm">
<i class="fas fa-search fa-fw" aria-hidden />
</b-button>

View file

@ -3,7 +3,7 @@
<template lang="html">
<div
:class="[
'list rounded pr-2',
'list rounded pr-3',
viewClass,
{
dragging,
@ -14,7 +14,7 @@
>
<b-card no-body>
<div
class="py-0 pr-0 pl-2 d-flex justify-content-between align-items-center"
class="p-1 pl-2 d-flex justify-content-between align-items-center"
>
<p class="list-name p-0 m-0">
<span v-b-modal="`rename-list-${listIndex}`">

View file

@ -1,9 +1,8 @@
<template lang="html">
<b-dropdown
right
size="sm"
variant="transparent"
toggle-class="m-1"
toggle-class="m-0"
>
<template v-slot:button-content>
<i class="fas fa-ellipsis-h fa-fw" aria-hidden />

View file

@ -0,0 +1,93 @@
<template lang="html">
<header class="p-2 d-flex">
<home-button />
<div class="toolbar pl-3">
<template v-if="$route.meta.title">
{{ $route.meta.title }}
</template>
<portal-target v-else name="pageTitle" />
<b-button
v-if="showBackButton"
size="sm"
:to="{ name: 'board', params: { id: board.id }}"
>
<i class="fas fa-arrow-left fa-fw" aria-hidden />
Back to {{ board.name }}
</b-button>
<template v-if="showBoardName">
{{ board.name }}
</template>
<div class="global-actions">
<portal-target name="headerActions" />
<b-button
:to="{ name: 'search' }"
size="sm"
>
<i class="fas fa-search fa-fw" aria-hidden />
</b-button>
<b-button
:to="{ name: 'settings' }"
class="ml-1"
size="sm"
>
<i class="fas fa-cog fa-fw" />
</b-button>
</div>
</div>
</header>
</template>
<script>
import GlobalSearch from '@/components/GlobalSearch';
import HomeButton from '@/components/Shared/HomeButton';
import { mapState } from 'vuex';
export default {
components: {
GlobalSearch,
HomeButton,
},
computed: {
...mapState(['board', 'boards']),
showBackButton() {
return this.$route.name === 'game' && this.board && this.board.id;
},
showBoardName() {
return this.$route.name === 'board' && this.board && this.board.name;
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
header {
display: grid;
align-items: center;
overflow-y: hidden;
height: 46px;
grid-template-columns: 65px 1fr;
}
.toolbar {
display: flex;
width: 100%;
align-items: center;
}
.global-actions {
margin-left: auto;
display: flex;
align-items: center;
}
</style>

View file

@ -1,6 +1,6 @@
<template lang="html">
<header class="my-3 d-flex align-items-center justify-content-between">
<h3 class="m-0">{{ title }}</h3>
<h5 class="m-0">{{ title }}</h5>
<b-button
v-if="actionText"

View file

@ -2,11 +2,11 @@
<div>
<!-- TODO: use PEGI/ESRB logos -->
<!-- <pre>{{ AGE_RATING_SYSTEMS }}</pre> -->
<div>
<!-- <div>
<b-card v-for="rating in AGE_RATING_SYSTEMS" :key="rating.name">
<pre class="text-dark">{{ rating }}</pre>
</b-card>
</div>
</div> -->
<b-form-group label="Game rating system:">
<b-form-select

View file

@ -0,0 +1,46 @@
<template lang="html">
<b-button
title="Dashboard"
size="sm"
class="home-button"
@click="handleLogoClick"
>
<!-- <img
src="/static/gamebrary-logo-dark.png"
width="32"
/> -->
<i class="fas fa-home" />
<!-- TODO: move back button to here when viewing a game that's part of a board -->
</b-button>
</template>
<script>
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['user']),
},
methods: {
handleLogoClick() {
if (!this.user) {
if (this.$route.name === 'public-boards') {
this.$bvModal.show('authModal');
} else {
this.$router.push({ name: 'public-boards' });
}
}
if (this.user && this.$route.name !== 'home') {
this.$router.push({ name: 'home' });
}
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.home-button {
width: 50px;
}
</style>

View file

@ -0,0 +1,97 @@
export const PLATFORM_CATEGORIES = {
1: 'console',
2: 'arcade',
3: 'platform',
4: 'os',
5: 'portable',
6: 'computer',
};
export const EXCLUDED_PLATFORMS = [
39,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
115,
116,
118,
121,
122,
125,
126,
127,
129,
131,
133,
134,
135,
138,
139,
140,
141,
142,
142,
143,
144,
145,
146,
147,
148,
149,
151,
152,
153,
154,
155,
156,
157,
158,
203,
236,
237,
238,
239,
240,
274,
308,
339,
372,
372,
373,
374,
375,
376,
44,
52, // Arcade
55,
69,
73,
74,
79, // Neogeo
82,
85,
89,
91,
95,
96,
97,
97,
98,
];
export const PLATFORM_OVERRIDES = {
12: {
slug: 'xbox-360',
},
};

View file

@ -2,10 +2,7 @@
<template lang="html">
<div
:class="[
'board p-3',
{ dragging, empty },
]"
:class="['board p-3', { dragging, empty }]"
:style="boardStyles"
>
<boards-dropdown />
@ -258,7 +255,7 @@ export default {
background-size: cover;
align-items: flex-start;
height: 100%;
width: 100%;
width: calc(100vw - 66px);
box-sizing: border-box;
overflow-x: auto;
overflow-x: overlay;

View file

@ -1,10 +1,12 @@
<template lang="html">
<b-container fluid>
<page-title
title="Boards"
action-text="Create board"
@action="$bvModal.show('create-board')"
/>
<portal to="header">
<page-title
title="Boards"
action-text="Create board"
@action="$bvModal.show('create-board')"
/>
</portal>
<boards v-if="boards.length" class="mb-3" />

View file

@ -1,19 +1,8 @@
<template lang="html">
<div class="mt-2 game-page" ref="gamePage">
<!-- <mini-board :board="board" v-if="board" /> -->
<div class="mb-2">
<b-button
v-if="board && board.id"
:to="{ name: 'board', params: { id: board.id }}"
>
<i class="fas fa-arrow-left fa-fw" aria-hidden />
Back to {{ board.name }}
</b-button>
</div>
<div class="p-3 game-page" ref="gamePage">
<!-- <pre>{{ speedruns }}</pre> -->
<b-skeleton v-if="loading" />
<game v-else-if="game" :game="game" />
<game v-else-if="game" :game="game" :gog="gog" :steam-game="steamGame" />
<!-- <div class="game-backdrop" :style="`background-image: url(${backdropUrl})`" /> -->
</div>
@ -21,25 +10,23 @@
<script>
import Game from '@/components/Game';
// import MiniBoard from '@/components/Board/MiniBoard';
import { mapState } from 'vuex';
export default {
components: {
Game,
// MiniBoard,
},
data() {
return {
game: {},
gog: null,
speedruns: null,
steamGame: null,
loading: false,
};
},
computed: {
...mapState(['board', 'boards']),
gameId() {
return this.$route.params.gameId;
},
@ -79,6 +66,34 @@ export default {
});
this.loading = false;
this.loadSupplementalData();
},
async loadSupplementalData() {
// TODO: put in constants
const gogCategoryId = 17;
const steamCategoryId = 13;
const gogPage = this.game.websites.find(({ category }) => category === gogCategoryId);
const steamPage = this.game.websites.find(({ category }) => category === steamCategoryId);
// const hasGog =
[this.speedruns] = (await this.$store.dispatch('LOAD_GAME_SPEEDRUNS', this.game.name)).data;
this.gog = gogPage
? await this.$store.dispatch('LOAD_GOG_GAME', this.game.name)
: null;
// console.log(steamPage);
// TODO: use regex or more elegant way to get id from url
const steamGameId = steamPage
? steamPage.url.split('app/')[1].split('/')[0]
: null;
this.steamGame = steamGameId
? await this.$store.dispatch('LOAD_STEAM_GAME', steamGameId)
: null;
},
},
};
@ -87,7 +102,6 @@ export default {
<style lang="scss" rel="stylesheet/scss" scoped>
.game-page {
z-index: 1;
// position: fixed;
}
.game-backdrop {

View file

@ -0,0 +1,22 @@
<template lang="html">
<div>
<pre>{{ platform }}</pre>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['platforms']),
platform() {
return this.platforms.find(({ slug }) => slug === this.$route.params.slug);
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
</style>

148
src/pages/PlatformsPage.vue Normal file
View file

@ -0,0 +1,148 @@
<template lang="html">
<div>
<b-button
variant="link"
v-for="platform in platforms"
:to="{ name: 'platform-page', params: { slug: platform.slug } }"
:key="platform.id"
>
<img :src="`static/logos/platforms-new/${platform.slug}.png`" />
{{ platform.slug }} | {{ platform.id }}
</b-button>
<!-- <img src="static/logos/platforms-new/3do.png" /> -->
<!-- <img src="static/logos/platforms-new/action-max.png" /> -->
<!-- <img src="static/logos/platforms-new/amiga-cd-3 2.png" /> -->
<!-- <img src="static/logos/platforms-new/arcadia-2001.png" /> -->
<!-- <img src="static/logos/platforms-new/astrocade.png" /> -->
<!-- <img src="static/logos/platforms-new/atari-2600.png" /> -->
<!-- <img src="static/logos/platforms-new/atari-5200.png" /> -->
<!-- <img src="static/logos/platforms-new/atari-7800.png" /> -->
<!-- <img src="static/logos/platforms-new/atari-xe.png" /> -->
<!-- <img src="static/logos/platforms-new/beena.png" /> -->
<!-- <img src="static/logos/platforms-new/cassette-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/cd-i.png" /> -->
<!-- <img src="static/logos/platforms-new/channel-f.png" /> -->
<!-- <img src="static/logos/platforms-new/coleco-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/commodore-cdtv.png" /> -->
<!-- <img src="static/logos/platforms-new/commodore64.png" /> -->
<!-- <img src="static/logos/platforms-new/cps-changer.png" /> -->
<!-- <img src="static/logos/platforms-new/creativision.png" /> -->
<!-- <img src="static/logos/platforms-new/dreamcast.png" /> -->
<!-- <img src="static/logos/platforms-new/family-computer.png" /> -->
<!-- <img src="static/logos/platforms-new/fm-towns-marty.png" /> -->
<!-- <img src="static/logos/platforms-new/game-wave.png" /> -->
<!-- <img src="static/logos/platforms-new/gamecube.png" /> -->
<!-- <img src="static/logos/platforms-new/genesis-32x.png" /> -->
<!-- <img src="static/logos/platforms-new/genesis.png" /> -->
<!-- <img src="static/logos/platforms-new/gx4000.png" /> -->
<!-- <img src="static/logos/platforms-new/halcyon.png" /> -->
<!-- <img src="static/logos/platforms-new/hyper-scan.png" /> -->
<!-- <img src="static/logos/platforms-new/imagination-machine.png" /> -->
<!-- <img src="static/logos/platforms-new/intellivision.png" /> -->
<!-- <img src="static/logos/platforms-new/interactive-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/ique.png" /> -->
<!-- <img src="static/logos/platforms-new/jaguar-cd.png" /> -->
<!-- <img src="static/logos/platforms-new/jaguar.png" /> -->
<!-- <img src="static/logos/platforms-new/konix.png" /> -->
<!-- <img src="static/logos/platforms-new/laser-active.png" /> -->
<!-- <img src="static/logos/platforms-new/leisure-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/loopy.png" /> -->
<!-- <img src="static/logos/platforms-new/mark-iii.png" /> -->
<!-- <img src="static/logos/platforms-new/mega-cd-ii.png" /> -->
<!-- <img src="static/logos/platforms-new/mega-cd.png" /> -->
<!-- <img src="static/logos/platforms-new/mega-drive.png" /> -->
<!-- <img src="static/logos/platforms-new/mega-ld.png" /> -->
<!-- <img src="static/logos/platforms-new/mp1000.png" /> -->
<!-- <img src="static/logos/platforms-new/my-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/neo-geo-cd.png" /> -->
<!-- <img src="static/logos/platforms-new/neo-geo.png" /> -->
<!-- <img src="static/logos/platforms-new/nes.png" /> -->
<!-- <img src="static/logos/platforms-new/nintendo-64-dd.png" /> -->
<!-- <img src="static/logos/platforms-new/nintendo-64.png" /> -->
<!-- <img src="static/logos/platforms-new/nuon.png" /> -->
<!-- <img src="static/logos/platforms-new/odyssey2.png" /> -->
<!-- <img src="static/logos/platforms-new/pc-engine.png" /> -->
<!-- <img src="static/logos/platforms-new/pc-fx.png" /> -->
<!-- <img src="static/logos/platforms-new/picno.png" /> -->
<!-- <img src="static/logos/platforms-new/pico.png" /> -->
<!-- <img src="static/logos/platforms-new/pippin.png" /> -->
<!-- <img src="static/logos/platforms-new/playdia.png" /> -->
<!-- <img src="static/logos/platforms-new/playstation.png" /> -->
<!-- <img src="static/logos/platforms-new/ps-2.png" /> -->
<!-- <img src="static/logos/platforms-new/ps3.png" /> -->
<!-- <img src="static/logos/platforms-new/ps4.png" /> -->
<!-- <img src="static/logos/platforms-new/pv-1000.png" /> -->
<!-- <img src="static/logos/platforms-new/rca-studio-ii.png" /> -->
<!-- <img src="static/logos/platforms-new/satellaview.png" /> -->
<!-- <img src="static/logos/platforms-new/sega-cd.png" /> -->
<!-- <img src="static/logos/platforms-new/sega-master-system.png" /> -->
<!-- <img src="static/logos/platforms-new/sega-saturn.png" /> -->
<!-- <img src="static/logos/platforms-new/sg-1000.png" /> -->
<!-- <img src="static/logos/platforms-new/socrates.png" /> -->
<!-- <img src="static/logos/platforms-new/super-acan.png" /> -->
<!-- <img src="static/logos/platforms-new/super-cassette-vision.png" /> -->
<!-- <img src="static/logos/platforms-new/super-cd-rom.png" /> -->
<!-- <img src="static/logos/platforms-new/super-famicom.png" /> -->
<!-- <img src="static/logos/platforms-new/super-grafx.png" /> -->
<!-- <img src="static/logos/platforms-new/super-nintendo.png" /> -->
<!-- <img src="static/logos/platforms-new/super-vision-8000.png" /> -->
<!-- <img src="static/logos/platforms-new/switch.png" /> -->
<!-- <img src="static/logos/platforms-new/turbo-grafx-16.png" /> -->
<!-- <img src="static/logos/platforms-new/tutor.png" /> -->
<!-- <img src="static/logos/platforms-new/tv-boy.png" /> -->
<!-- <img src="static/logos/platforms-new/ultravision.png" /> -->
<!-- <img src="static/logos/platforms-new/v-flash.png" /> -->
<!-- <img src="static/logos/platforms-new/v-smile.png" /> -->
<!-- <img src="static/logos/platforms-new/vc4000.png" /> -->
<!-- <img src="static/logos/platforms-new/vectrex.png" /> -->
<!-- <img src="static/logos/platforms-new/video-art.png" /> -->
<!-- <img src="static/logos/platforms-new/video-challenger.png" /> -->
<!-- <img src="static/logos/platforms-new/video-driver.png" /> -->
<!-- <img src="static/logos/platforms-new/videopac.png" /> -->
<!-- <img src="static/logos/platforms-new/vis.png" /> -->
<!-- <img src="static/logos/platforms-new/wii-u.png" /> -->
<!-- <img src="static/logos/platforms-new/wii.png" /> -->
<!-- <img src="static/logos/platforms-new/xavix.png" /> -->
<!-- <img src="static/logos/platforms-new/xbox-360.png" /> -->
<!-- <img src="static/logos/platforms-new/xbox-one.png" /> -->
<!-- <img src="static/logos/platforms-new/xbox.png" /> -->
<!-- <img src="static/logos/platforms-new/zeebo.png" /> -->
<!-- <img src="static/logos/platforms-new/zemina.png" /> -->
<!-- <pre class="text-dark small">{{ platforms }}</pre> -->
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['platforms']),
},
mounted() {
this.loadPlatforms();
},
methods: {
async loadPlatforms() {
await this.$store.dispatch('LOAD_IGDB_PLATFORMS')
.catch(() => {
this.$bvToast.toast('There was an error loading platforms', { variant: 'error' });
});
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
img {
filter: drop-shadow(-1px 0 0 black)
drop-shadow(0 -1px 0 black)
drop-shadow(0 1px 0 black)
drop-shadow(1px 0 0 black);
width: 200px;
}
</style>

View file

@ -1,41 +1,69 @@
<template lang="html">
<b-container fluid class="mt-2">
<page-title
title="Search"
<div class="search-page p-3">
<b-form-input
v-model="searchText"
type="search"
autofocus
debounce="500"
class="mb-4"
:placeholder="$t('board.addGame.inputPlaceholder')"
@update="search"
/>
<b-form inline>
<label class="sr-only" for="inline-form-input-name">Name</label>
<b-form-input
v-model="text"
placeholder="Search"
type="search"
trim
<b-list-group
v-for="{ id } in searchResults"
:key="id"
@click="openGame(id)"
>
<game-card-search
:game-id="id"
class="mb-2"
/>
<label class="sr-only" for="inline-form-input-username">Username</label>
<b-input-group prepend="@" class="mb-2 mr-sm-2 mb-sm-0">
<b-form-input id="inline-form-input-username" placeholder="Username"></b-form-input>
</b-input-group>
<!-- <b-form-checkbox class="mb-2 mr-sm-2 mb-sm-0">Remember me</b-form-checkbox> -->
<b-button variant="light">Search</b-button>
</b-form>
<div>
results here
</div>
</b-container>
</b-list-group>
</div>
</template>
<script>
import GameCardSearch from '@/components/GameCards/GameCardSearch';
export default {
components: {
GameCardSearch,
},
data() {
return {
text: '',
searchText: '',
searchResults: [],
};
},
methods: {
openGame(gameId) {
// TODO: handle game detail view setting
// this.$store.commit('SET_GAME_MODAL_DATA', { gameId });
// this.$bvModal.show('game-modal');
this.$store.commit('SET_GAME_MODAL_DATA', { gameId });
this.$router.push({
name: 'game',
params: {
gameId,
// gameSlug: this.games[gameId].slug,
},
});
},
async search(searchText) {
if (!searchText) {
this.searchResults = [];
return;
}
this.searchResults = await this.$store.dispatch('CUSTOM_SEARCH', { searchText });
},
},
};
</script>

View file

@ -1,7 +1,5 @@
<template lang="html">
<b-container fluid>
<page-title title="Settings" />
<b-row no-gutters>
<b-col cols="2">
<b-list-group>

View file

@ -7,6 +7,8 @@ import ProfileSettingsPage from '@/pages/ProfileSettingsPage';
import ExplorePage from '@/pages/ExplorePage';
import GamePage from '@/pages/GamePage';
import HomePage from '@/pages/HomePage';
import PlatformsPage from '@/pages/PlatformsPage';
import PlatformPage from '@/pages/PlatformPage';
import NotFoundPage from '@/pages/NotFoundPage';
import NotesPage from '@/pages/NotesPage';
import PrivacyPolicyPage from '@/pages/PrivacyPolicyPage';
@ -41,6 +43,19 @@ const routes = [
title: 'DevTools',
},
},
{
name: 'platforms',
path: '/platforms',
component: PlatformsPage,
meta: {
title: 'Platforms',
},
},
{
path: '/platforms/:slug',
name: 'platform-page',
component: PlatformPage,
},
{
name: 'settings',
path: '/settings',
@ -107,6 +122,9 @@ const routes = [
path: '/search',
name: 'search',
component: SearchPage,
meta: {
title: 'Search',
},
},
{
name: 'explore',

View file

@ -8,6 +8,15 @@ const API_BASE = 'https://us-central1-gamebrary-8c736.cloudfunctions.net';
// const API_BASE = 'http://localhost:5001/gamebrary-8c736/us-central1';
export default {
LOAD_GAME_SPEEDRUNS(context, gameName) {
return new Promise((resolve, reject) => {
axios.get(`https://www.speedrun.com/api/v1/games?name=${gameName}`)
.then(({ data }) => {
resolve(data);
}).catch(reject);
});
},
LOAD_IGDB_PLATFORMS({ state, commit }) {
return new Promise((resolve, reject) => {
axios.get(`${API_BASE}/platforms?token=${state.twitchToken.access_token}`)
@ -56,6 +65,24 @@ export default {
});
},
LOAD_STEAM_GAME(context, steamGameId) {
return new Promise((resolve, reject) => {
// axios.get(`${API_BASE}/steam-game?gameId=${steamGameId}`)
axios.get(`http://localhost:5001/gamebrary-8c736/us-central1/steam-game?gameId=${steamGameId}`)
.then(({ data }) => {
const steamGameData = data[steamGameId];
const gameData = steamGameData.success
? steamGameData.data
: null;
console.log(gameData);
resolve(gameData);
}).catch(reject);
});
},
LOAD_BOARDS({ state, commit }) {
return new Promise((resolve, reject) => {
const db = firebase.firestore();
@ -449,6 +476,19 @@ export default {
});
},
LOAD_GOG_GAME(context, search) {
return new Promise((resolve, reject) => {
axios.get(`http://localhost:5001/gamebrary-8c736/us-central1/gog?search=${search}`)
.then(({ data }) => {
const game = data.totalGamesFound
? data.products[0]
: null;
resolve(game);
}).catch(reject);
});
},
SEARCH_BOARD_GAMES({ commit, state }, searchText) {
const platforms = state.board.platforms.length > 0
? `&platform=${state.board.platforms.join(',')}`

View file

@ -1,5 +1,5 @@
// import { PLATFORM_FILTER_FIELDS } from '@/constants';
import { AGE_RATING_SYSTEMS } from '@/constants';
import { PLATFORM_CATEGORIES, EXCLUDED_PLATFORMS, PLATFORM_OVERRIDES } from '@/constants/platforms';
import orderby from 'lodash.orderby';
export default {
@ -44,6 +44,22 @@ export default {
return formattedPlatforms;
},
platforms: (state) => {
const platforms = state.platforms
.filter(({ id }) => !EXCLUDED_PLATFORMS.includes(id))
.map(platform => ({
// ...platform,
id: platform.id,
generation: platform.generation,
name: platform.name,
slug: platform.slug,
category: PLATFORM_CATEGORIES[platform.category],
...PLATFORM_OVERRIDES[platform.id],
}));
return platforms;
},
gameAgeRatings: () => (game) => {
const ageRatings = game && game.age_ratings;

View file

@ -1,12 +1,12 @@
import Vue from 'vue';
import {
PLATFORM_CATEGORIES,
EXCLUDED_PLATFORMS,
PLATFORM_BG_HEX,
PLATFORM_LOGO_FORMAT,
PLATFORM_NAME_OVERRIDES,
POPULAR_PLATFORMS,
} from '@/constants';
// import {
// // PLATFORM_CATEGORIES,
// // EXCLUDED_PLATFORMS,
// // PLATFORM_BG_HEX,
// // PLATFORM_LOGO_FORMAT,
// // PLATFORM_NAME_OVERRIDES,
// // POPULAR_PLATFORMS,
// } from '@/constants';
export default {
SET_BOARDS(state, boards) {
@ -66,23 +66,24 @@ export default {
SET_PLATFORMS(state, platforms) {
// TODO: use getter instead to get fresh data right away instead of once per session
state.platforms = platforms
.filter(({ id }) => !EXCLUDED_PLATFORMS.includes(id))
.map((platform) => {
const formattedPlatform = {
id: platform.id,
name: PLATFORM_NAME_OVERRIDES[platform.id] || platform.name,
slug: platform.slug,
category: PLATFORM_CATEGORIES[platform.category],
popular: POPULAR_PLATFORMS.includes(platform.id),
// categoryId: platform.category,
generation: platform.generation || 0,
bgHex: PLATFORM_BG_HEX[platform.id] || null,
logoFormat: PLATFORM_LOGO_FORMAT[platform.id] || 'svg',
};
return formattedPlatform;
});
state.platforms = platforms;
// state.platforms = platforms
// .filter(({ id }) => !EXCLUDED_PLATFORMS.includes(id))
// .map((platform) => {
// const formattedPlatform = {
// id: platform.id,
// name: PLATFORM_NAME_OVERRIDES[platform.id] || platform.name,
// slug: platform.slug,
// category: PLATFORM_CATEGORIES[platform.category],
// popular: POPULAR_PLATFORMS.includes(platform.id),
// // categoryId: platform.category,
// generation: platform.generation || 0,
// bgHex: PLATFORM_BG_HEX[platform.id] || null,
// logoFormat: PLATFORM_LOGO_FORMAT[platform.id] || 'svg',
// };
//
// return formattedPlatform;
// });
},
SET_BOARD_GAMES(state, boardGames) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Some files were not shown because too many files have changed in this diff Show more