This commit is contained in:
Gamebrary 2022-08-17 22:12:05 -07:00
parent f0317747a5
commit e237b735ba
17 changed files with 293 additions and 358 deletions

View file

@ -2,13 +2,14 @@
<b-sidebar
id="addGame"
no-header
right
:visible="Boolean(gameId)"
backdrop
shadow
@hidden="hidden"
>
<template #default>
<div class="p-2">
<div class="p-2 bg-white">
<b-link :to="{ name: 'game', params: { id: game.id, slug: game.slug }}">
<b-img
:src="coverUrl"
@ -17,78 +18,75 @@
/>
</b-link>
<b-button
block
variant="success"
class="mt-2"
:to="{ name: 'game', params: { id: game.id, slug: game.slug }}"
>
{{ game.name }}
</b-button>
<template v-if="user">
<h4 class="my-2">Add to list:</h4>
<h4 class="my-3 text-center">Add to list:</h4>
<b-list-group flush>
<b-list-group-item
v-for="board in formattedBoards"
:key="board.id"
class="p-0"
button
@click="expandedBoard = board.id === expandedBoard ? null : board.id"
<div
v-for="board in formattedBoards"
:key="board.id"
class="p-2 bg-light mb-2"
>
<header class="mb-2 d-flex align-items-center">
<b-avatar
rounded
:class="['board-thumbnail mr-2', { 'bg-dark' : !board.backgroundColor }]"
:title="board.name"
text=" "
size="32"
:style="`
background-image: url(${board.backgroundUrl ? board.backgroundUrl : ''});
background-color: ${board.backgroundColor ? board.backgroundColor : ''}
`"
:to="{ name: 'board', params: { id: board.id } }"
/>
{{ board.name }}
</header>
<b-button
v-for="(list, listIndex) in board.lists"
:key="`${board.id}-${list.name}`"
:variant="isGameInList({ list, gameId }) ? 'success' : 'info'"
block
clas
size="sm"
@click.stop="handleClick({ list, listIndex, board })"
>
<header class="p-2 d-flex justify-content-between align-items-center">
<aside class="d-flex">
<b-avatar
rounded
:class="['board-thumbnail mr-2', { 'bg-dark' : !board.backgroundColor }]"
:title="board.name"
text=" "
:style="`
background-image: url(${board.backgroundUrl ? board.backgroundUrl : ''});
background-color: ${board.backgroundColor ? board.backgroundColor : ''}
`"
:to="{ name: 'board', params: { id: board.id } }"
/>
{{ list.name }}
<div class="d-flex flex-column">
{{ board.name }}
<b-badge variant="light" class="mr-2">
{{ list.games.length }}
</b-badge>
<i :class="`fa-solid ${isGameInList({ list, gameId }) ? 'fa-minus' : 'fa-plus' }`" />
</b-button>
<!-- <b-collapse
:id="board.id"
:visible="expandedBoard === board.id"
accordion="my-accordion"
role="tabpanel"
>
<b-list-group flush>
<div
class="d-flex justify-content-between align-items-center"
v-for="(list, listIndex) in board.lists"
:key="`${board.id}-${list.name}`"
:variant="isGameInList({ list, gameId }) ? 'success' : 'transparent'"
button
@click.stop="handleClick({ list, listIndex, board })"
>
<span>
{{ list.name }}
<br />
<small>{{ board.lists.length }} Lists</small>
</div>
<!-- TODO: show "In XX lists" -->
</aside>
<small class="text-muted">{{ list.games.length }} games in list</small>
</span>
<b-badge variant="primary" pill>{{ board.lists.length }}</b-badge>
</header>
<b-collapse
:id="board.id"
:visible="expandedBoard === board.id"
accordion="my-accordion"
role="tabpanel"
>
<b-list-group flush>
<b-list-group-item
class="d-flex justify-content-between align-items-center"
v-for="(list, listIndex) in board.lists"
:key="`${board.id}-${list.name}`"
:variant="isGameInList({ list, gameId }) ? 'success' : 'transparent'"
button
@click.stop="handleClick({ list, listIndex, board })"
>
<span>
{{ list.name }}
<br />
<small class="text-muted">{{ list.games.length }} games in list</small>
</span>
<i :class="`fa-solid ${isGameInList({ list, gameId }) ? 'fa-minus' : 'fa-plus' }`" />
</b-list-group-item>
</b-list-group>
</b-collapse>
</b-list-group-item>
</b-list-group>
<i :class="`fa-solid ${isGameInList({ list, gameId }) ? 'fa-minus' : 'fa-plus' }`" />
</div>
</b-list-group>
</b-collapse> -->
</div>
</template>
<b-button
@ -118,6 +116,8 @@ export default {
mounted() {
this.$bus.$on('ADD_GAME', this.setGame);
this.setGame(1026);
},
computed: {

View file

@ -2,8 +2,8 @@
<b-card
no-body
:title="game.name"
class="mb-3"
:footer-class="['p-1 text-center font-weight-bold bold strong', selected ? 'bg-success' : 'text-muted']"
class="mb-3 cursor-pointer"
:footer-class="['p-1 text-center \ font-weight-bold bold strong', selected ? 'bg-success' : 'text-muted']"
@click="handleClick"
>
<!-- :to="{ name: 'game', params: { id: game.id, slug: game.slug }}" -->

View file

@ -31,45 +31,6 @@
{{ $t(`shortcuts.${name.substr(6)}`) }}
</p>
<div class="bg-secondary p-2 rounded">
<p>Game modal shortucts</p>
<p>
<kbd class="mr-1">
<i class="fas fa-angle-left fa-fw" aria-hidden />
</kbd>
Previous game
</p>
<p>
<kbd class="mr-1">
<i class="fas fa-angle-right fa-fw" aria-hidden />
</kbd>
Next game
</p>
<p>
<kbd class="mr-1">
T
</kbd>
Game Tags
</p>
<p>
<kbd class="mr-1">
N
</kbd>
Game notes
</p>
<p>
<kbd class="mr-1">
P
</kbd>
Game progress
</p>
</div>
</b-modal>
</template>

View file

@ -1,42 +0,0 @@
<template lang="html">
<b-card v-if="provider" style="max-width: 100%; width: 400px;" class="mb-3">
<b-media>
<template #aside>
<b-img
:src="`/logos/companies/${provider.id}.svg`"
width="40"
alt="Provider"
/>
</template>
<h4>{{ user.displayName }}</h4>
<p class="m-0">Logged in {{ lastLogin }} using <strong>{{ provider.name }}</strong>.</p>
</b-media>
</b-card>
</template>
<script>
import { AUTH_PROVIDERS } from '@/constants';
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['user']),
provider() {
return AUTH_PROVIDERS[this.user.providerId];
},
dateJoined() {
return this.$dayjs(this.user?.dateJoined).format('M/D/YYYY');
},
lastLogin() {
return this.$dayjs(this.user?.lastLogin).format('M/D/YYYY');
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
</style>

View file

@ -17,6 +17,38 @@
Select
</b-button>
<b-dropdown
variant="light"
class="mr-2"
menu-class="p-0"
>
<template #button-content>
<b-spinner v-if="saving" small />
<span v-else>Set as wallpaper</span>
</template>
<b-dropdown-item
v-for="board in formattedBoards"
:key="board.id"
@click="setAsWallpaper(board)"
class="p-0"
>
<b-avatar
rounded
:class="['board-thumbnail mr-2', { 'bg-dark' : !board.backgroundColor }]"
:title="board.name"
text=" "
size="32"
:style="`
background-image: url(${board.backgroundUrl ? board.backgroundUrl : ''});
background-color: ${board.backgroundColor ? board.backgroundColor : ''}
`"
/>
{{ board.name }}
</b-dropdown-item>
</b-dropdown>
<b-button
variant="danger"
@click.stop="confirmDeleteWallpaper(wallpaper)"
@ -27,15 +59,22 @@
</template>
<b-img
v-if="wallpaper && wallpaper.url"
:src="wallpaper.url"
v-if="wallpaperUrl"
:src="wallpaperUrl"
class="w-100 rounded"
/>
</b-modal>
</template>
<script>
import { mapState } from 'vuex';
export default {
data() {
return {
saving: false,
};
},
props: {
selectable: Boolean,
wallpaper: {
@ -44,7 +83,28 @@ export default {
},
},
computed: {
...mapState(['boards', 'wallpapers']),
formattedBoards() {
return this.boards.map((board) => ({ ...board, backgroundUrl: this.getWallpaperUrl(board.backgroundUrl) }));
},
wallpaperUrl() {
return this.wallpaper?.url;
},
},
methods: {
getWallpaperUrl(url) {
if (!url) return null;
if (url?.includes('igdb.com')) return url;
const wallpaper = this.wallpapers?.find(({ fullPath }) => fullPath === url);
return wallpaper?.url;
},
select() {
this.$emit('selected', this.wallpaper);
@ -72,9 +132,31 @@ export default {
this.$bvModal.hide('previewWallpaper');
},
async setAsWallpaper(board) {
const payload = {
...board,
backgroundUrl: this.wallpaper.fullPath,
}
this.saving = true;
this.$store.commit('SET_ACTIVE_BOARD', payload);
await this.$store.dispatch('SAVE_BOARD')
.catch(() => {
this.saving = false;
});
this.saving = false;
this.$bvModal.hide('previewWallpaper');
},
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
.board-thumbnail {
background-size: cover;
background-position: center;
}
</style>

View file

@ -75,9 +75,9 @@ export const GENRE_ICONS = {
export const KEYBOARD_SHORTCUTS = {
'MODAL_keyboard-shortcuts': ['shift', '?'],
'MODAL_create-board': ['shift', 'c'],
// MODAL_devTools: ['shift', 'd'],
ROUTE_boards: ['shift', 'b'],
ROUTE_home: ['shift', 'h'],
ROUTE_search: ['shift', 'k'],
ROUTE_tags: ['shift', 't'],
ROUTE_notes: ['shift', 'n'],
ROUTE_wallpapers: ['shift', 'w'],

View file

@ -21,7 +21,8 @@
},
"shortcuts": {
"keyboard-shortcuts": "Open this modal",
"create-board": "Create new board",
"home": "Go to home",
"search": "Go to search",
"boards": "Go to boards",
"tags": "Go to tags",
"notes": "Go to notes",

View file

@ -1,46 +0,0 @@
<template lang="html">
<b-container>
<provider-card />
<delete-account-modal />
<div class="mb-3">
<b-button
class="mr-3"
variant="danger"
v-b-modal:deleteAccount
>
Delete Account
</b-button>
<b-button
@click="session_signOut"
>
<i class="fa-solid fa-arrow-right-from-bracket" />
Log out
</b-button>
</div>
</b-container>
</template>
<script>
import DeleteAccountModal from '@/components/Settings/DeleteAccountModal';
import ProviderCard from '@/components/ProviderCard';
import { mapState } from 'vuex';
import sessionMixin from '@/mixins/sessionMixin';
export default {
components: {
ProviderCard,
DeleteAccountModal,
},
mixins: [sessionMixin],
computed: {
...mapState(['user']),
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
</style>

View file

@ -77,9 +77,7 @@
@click="deleteNote"
>
<b-spinner small v-if="deleting" />
<i class="d-sm-none fas fa-trash fa-fw" aria-hidden />
<span class="d-none d-sm-inline">{{ $t('global.delete') }}</span>
<i v-else class="fas fa-trash fa-fw" aria-hidden />
</b-button>
</footer>
@ -162,26 +160,19 @@ export default {
},
async deleteNote() {
// this.deleting = true;
//
// this.$store.commit('REMOVE_GAME_NOTE', this.game.id);
//
// await this.$store.dispatch('SAVE_NOTES_NO_MERGE')
// .catch(() => {
// this.deleting = false;
// this.$bvToast.toast('There was an error deleting your note', { variant: 'danger' });
// });
//
// this.note = '';
// this.$bvToast.toast('Note deleted');
//
// this.$router.push({
// name: 'game',
// params: {
// id: this.game.id,
// slug: this.game.slug,
// },
// });
this.deleting = true;
this.$store.commit('REMOVE_GAME_NOTE', this.game.id);
await this.$store.dispatch('SAVE_NOTES_NO_MERGE')
.catch(() => {
this.deleting = false;
this.$bvToast.toast('There was an error deleting your note', { variant: 'danger' });
});
this.note = '';
this.$router.push({ name: 'game', params: { id: this.game.id, slug: this.game.slug } });
},
},
};

View file

@ -16,6 +16,43 @@
</div>
<template v-else-if="game">
<portal to="headerActions">
<b-button
v-if="!tagsApplied.length"
rounded
variant="light"
class="mr-2"
@click="$router.push({ name: 'game.tags', params: { id: game.id, slug: game.slug } })"
>
<i class="fa-solid fa-tags" />
</b-button>
<b-button
variant="light"
class="mr-2"
@click="$router.push({ name: 'game.progress', params: { id: game.id, slug: game.slug } })"
>
<template v-if="progress">
{{ progress }}%
</template>
<i v-else class="fa-solid fa-stopwatch" />
</b-button>
<b-button
:to="{ name: 'game.notes', params: { id: game.id, slug: game.slug } }"
variant="light"
class="mr-2"
>
<i class="fa-solid fa-note-sticky fa-fw" />
</b-button>
<b-button
variant="light" @click="$bus.$emit('ADD_GAME', game.id)"
class="mr-2"
>
<i class="fa-solid fa-plus fa-fw" />
</b-button>
</portal>
<game-media-modal />
<b-form-row>
@ -125,42 +162,6 @@
<game-titles />
<aside>
<b-button
v-if="!tagsApplied.length"
rounded
variant="light"
size="sm"
class="mr-1"
@click="$router.push({ name: 'game.tags', params: { id: game.id, slug: game.slug } })"
>
Tag
</b-button>
<b-button
variant="light"
size="sm"
class="mr-1"
@click="$router.push({ name: 'game.progress', params: { id: game.id, slug: game.slug } })"
>
{{ progress || 0 }}%
</b-button>
<b-button
size="sm"
variant="warning" :to="{ name: 'game.notes', params: { id: game.id, slug: game.slug } }"
class="mr-1"
>
<i class="fa-solid fa-note-sticky fa-fw" />
</b-button>
<b-button
size="sm"
variant="light" @click="$bus.$emit('ADD_GAME', game.id)"
class="mr-1"
>
<i class="fa-solid fa-plus fa-fw" />
</b-button>
<!-- <b-button :href="metacriticScore.url" variant="success" v-if="metacriticScore.url">
{{ metacriticScore.score }}

View file

@ -1,70 +1,58 @@
<template lang="html">
<b-container>
<portal to="pageTitle">
<span>
<div>
<b-button
:to="{ name: 'game', params: { id: game.id, slug: game.slug }}"
:to="{ name: 'game', params: { id: game.id, slug: game.slug } }"
variant="light"
class="mr-2"
>
{{ game.name }}
<i class="fa-solid fa-chevron-left" />
</b-button>
Track progress
</span>
</div>
</portal>
<router-link :to="{ name: 'game', params: { id: game.id, slug: game.slug }}">
<b-img :src="gameCoverUrl" width="200" rounded class="mb-2 mr-2" />
</router-link>
{{ title }}
<b-row>
<b-col cols="6">
<router-link :to="{ name: 'game', params: { id: game.id, slug: game.slug }}" class="float-right">
<b-img :src="gameCoverUrl" fluid rounded />
</router-link>
</b-col>
<b-progress
:value="localProgress"
:max="100"
show-progress
variant="success"
striped
height="2rem"
/>
<!-- TODO: animate when saving! -->
<!-- animated -->
<b-button
v-if="!saving"
variant="success"
@click="markAsCompleted"
>
<i class="fas fa-check fa-fw" aria-hidden />
Mark as completed
</b-button>
<b-col>
<b-input-group :prepend="`${localProgress}%`" class="field mb-2">
<b-form-input
size="lg"
v-model="localProgress"
type="range"
max="100"
step="1"
/>
</b-input-group>
<b-button
:disabled="deleting"
variant="danger"
@click="deleteProgress"
>
<i class="fas fa-trash fa-fw" aria-hidden />
Remove progress
</b-button>
<b-button
variant="primary"
:disabled="saving"
class="mr-2"
@click="saveProgress"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button>
<b-button
variant="primary"
:disabled="saving"
@click="saveProgress"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button>
<b-input-group :prepend="`${localProgress}%`" size="lg">
<b-form-input
size="lg"
v-model="localProgress"
type="range"
max="100"
step="1"
/>
</b-input-group>
<b-button
:disabled="deleting"
variant="danger"
@click="deleteProgress"
>
<b-spinner small v-if="deleting" />
<i v-else class="fas fa-trash fa-fw" aria-hidden />
</b-button>
</b-col>
</b-row>
</b-container>
</template>
@ -102,12 +90,6 @@ export default {
},
methods: {
markAsCompleted() {
this.localProgress = 100;
this.saveProgress();
},
show() {
this.setGameProgress();
this.saving = false;
@ -135,8 +117,8 @@ export default {
this.deleting = false;
});
this.$bvToast.toast('Progress deleted', { title: `${name} progress`, variant: 'success' });
this.$bvModal.hide('progress');
this.deleting = false;
this.$router.push({ name: 'game', params: { id: this.game.id, slug: this.game.slug }});
},
async saveProgress() {
@ -155,8 +137,8 @@ export default {
this.$bvToast.toast('There was an error saving your progress', { variant: 'error' });
});
this.$bvToast.toast('Progress updated', { title: `${name} progress`, variant: 'success' });
this.$bvModal.hide('progress');
this.saving = false;
this.$router.push({ name: 'game', params: { id: this.game.id, slug: this.game.slug }});
},
},
};

View file

@ -1,9 +1,9 @@
<template lang="html">
<b-container fluid>
<b-container>
<portal to="pageTitle">
<div>
<b-button
:to="gamePage"
:to="{ name: 'game', params: { id: game.id, slug: game.slug } }"
variant="light"
class="mr-2"
>
@ -29,7 +29,7 @@
<b-row v-else>
<b-col cols="6">
<router-link :to="{ name: 'game', params: { id: game.id, slug: game.slug }}" class="float-right">
<b-img :src="gameCoverUrl" fluid rounded class="mb-2 mr-2 field" />
<b-img :src="gameCoverUrl" fluid rounded />
</router-link>
</b-col>
@ -116,10 +116,6 @@ export default {
return this.game?.name.length > 25;
},
gamePage() {
return { name: 'game', params: { id: this.game?.id, slug: this.game?.slug }};
},
empty() {
return Object.keys(this.tags).length === 0;
},

View file

@ -39,25 +39,25 @@
:key="index"
cols="8"
>
<aside v-if="game">
<router-link
v-if="game"
tag="div"
class="d-flex rounded bg-light p-2 mb-2 cursor-pointer"
:to="{ name: 'game.notes', params: { id: game.id, slug: game.slug }}"
>
<b-img
:src="getCoverUrl(game.id)"
class="cursor-pointer "
width="40"
/>
<b-button
v-if="game.name"
variant="link"
>
{{ game.name }}
</b-button>
<p class="text-muited small" v-if="filteredNotes[index]">
{{ filteredNotes[index].note }}
</p>
</aside>
<div class="ml-2">
<h5>{{ game.name }}</h5>
<p class="text-muted small" v-if="filteredNotes[index]">
{{ filteredNotes[index].note }}
</p>
</div>
</router-link>
</b-col>
</b-form-row>
</b-container>

View file

@ -13,7 +13,7 @@
<b-row v-else-if="searchResults.length">
<b-col cols="12" class="bg-light py-2 mb-3" v-if="activeBoard">
<pre>{{ activeBoard }}</pre>
<!-- <pre>{{ activeBoard }}</pre> -->
<!-- <b-button
v-if="activeBoard"
@ -44,6 +44,11 @@
<b-button v-if="activeBoard">
{{ activeBoardList.name }}
</b-button>
<b-button :to="{ name: 'search' }">
<i class="fas fa-times fa-fw" aria-hidden />
Clear
</b-button>
</b-col>
<b-col

View file

@ -26,12 +26,13 @@
@click.native="$router.push({ name: 'tags' })"
/>
<settings-card
title="Account"
description="Manage your Gamebrary account"
icon="fa-user"
@click.native="$router.push({ name: 'account.settings' })"
/>
<b-button
block
@click="session_signOut"
>
<i class="fa-solid fa-arrow-right-from-bracket" />
Log out
</b-button>
<!-- TODO: fix and reenable -->
<!-- <b-button
@ -50,6 +51,8 @@
Dev tools
</b-button> -->
<delete-account-modal />
<b-button
href="https://github.com/romancm/gamebrary"
target="_blank"
@ -119,9 +122,12 @@ import SettingsCard from '@/components/Settings/SettingsCard';
// import GameDetailSettings from '@/components/Settings/GameDetailSettings';
// import LanguageSettings from '@/components/Settings/LanguageSettings';
import { mapState } from 'vuex';
import sessionMixin from '@/mixins/sessionMixin';
import DeleteAccountModal from '@/components/Settings/DeleteAccountModal';
export default {
components: {
DeleteAccountModal,
// LanguageSettings,
// GameDetailSettings,
// ProfileSettingsPage,
@ -130,6 +136,8 @@ export default {
// GeneralSettingsPage,
},
mixins: [sessionMixin],
computed: {
...mapState(['user']),
},

View file

@ -5,7 +5,6 @@ import AboutPage from '@/pages/AboutPage';
import AuthPage from '@/pages/AuthPage';
import BoardPage from '@/pages/BoardPage';
import UpgradePage from '@/pages/UpgradePage';
import AccountSettingsPage from '@/pages/AccountSettingsPage';
import EditBoardPage from '@/pages/EditBoardPage';
import CreateBoardPage from '@/pages/CreateBoardPage';
import DevToolsPage from '@/pages/DevToolsPage';
@ -85,14 +84,6 @@ const routes = [
title: "Steam",
},
},
{
name: 'account.settings',
path: '/settings/account',
component: AccountSettingsPage,
meta: {
title: "Steam",
},
},
{
name: 'tags',
path: '/tags',

View file

@ -6,4 +6,9 @@
.spinner-centered {
position: absolute;
left: calc(50% - 16px);
}
.dropdown-menu {
height: 320px;
overflow-y: auto;
}