UX Updates

This commit is contained in:
Gamebrary 2022-07-05 14:08:15 -07:00
parent 53f10564b5
commit de132c2286
16 changed files with 341 additions and 277 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1,3 +1,4 @@
<!-- TODO: Use moment? or use dayjs without wrapper -->
<!-- TODO: remove toasts -->
<!-- TODO: add mega search shift + k -->
<!-- TODO: re-translate strings -->
@ -23,17 +24,18 @@
@shortkey="handleShortcutAction"
>
<page-header />
<main :class="[{ 'authorizing': !user }, 'bg-light']">
<global-modals />
<router-view />
</main>
<router-view class="viewport" />
<auth-modal />
<keyboard-shortcuts-modal />
<add-remove-game />
</div>
</template>
<script>
import AuthModal from '@/components/AuthModal';
import AddRemoveGame from '@/components/AddRemoveGame';
import KeyboardShortcutsModal from '@/components/KeyboardShortcutsModal';
import PageHeader from '@/components/PageHeader';
import GlobalModals from '@/components/GlobalModals';
import sessionMixin from '@/mixins/sessionMixin';
import firebase from 'firebase/app';
import { mapState } from 'vuex';
@ -46,7 +48,9 @@ export default {
components: {
PageHeader,
GlobalModals,
AuthModal,
AddRemoveGame,
KeyboardShortcutsModal,
},
mixins: [sessionMixin],
@ -130,17 +134,14 @@ export default {
<style lang="scss" rel="stylesheet/scss" scoped>
#app {
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(0,212,255,1) 100%);
height: 100vh;
// background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(0,212,255,1) 100%);
min-height: 100vh;
display: grid;
}
header {
grid-column: 1/-1;
}
main {
.viewport {
// padding-top: 54px !important;
overflow-y: auto;
height: calc(100vh - 54px);
// height: calc(100vh - 54px);
}
</style>

View file

@ -22,7 +22,7 @@
</header>
<!-- TODO: show active board at top -->
Boards:
<h4 class="mx-2">Boards:</h4>
<b-list-group flush>
<b-list-group-item
v-for="board in formattedBoards"
@ -32,7 +32,7 @@
@click="expandedBoard = board.id === expandedBoard ? null : board.id"
>
<header class="p-2 d-flex justify-content-between align-items-center">
<aside>
<aside class="d-flex">
<b-avatar
rounded
:class="['board-thumbnail mr-2', { 'bg-dark' : !board.backgroundColor }]"
@ -44,7 +44,12 @@
`"
:to="{ name: 'board', params: { id: board.id } }"
/>
{{ board.name }}
<div class="d-flex flex-column">
{{ board.name }}
<br />
<small>{{ board.lists.length }} Lists</small>
</div>
<!-- TODO: show "In XX lists" -->
</aside>

View file

@ -10,13 +10,12 @@
Edit board
</b-button>
<b-button
v-b-modal.add-list
<!-- <b-button
block
variant="primary"
>
Add list
</b-button>
</b-button> -->
</div>
</template>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div v-if="game" class="mt-4 d-block">
<div v-if="game">
<b-button
v-for="{ url, id, icon, svg } in links"
:href="url"

View file

@ -1,23 +1,22 @@
<template lang="html">
<b-card v-if="similarGames.length">
<h4 class="text-center">You may also like:</h4>
<div v-if="similarGames.length">
<h4 class="text-center text-muted">You may also like</h4>
<div class="d-flex overflow-auto">
<b-card
v-for="game in similarGames"
:key="game.id"
:title="game.name"
title-tag="small"
class="flex-shrink-0 mr-2 cursor-pointer"
style="max-width: 120px;"
body-class="p-1 px-2"
style="max-width: 180px;"
body-class="p-2 text-center text-muted"
:img-src="getCoverUrl(game)"
:img-alt="game.name"
img-top
@click="openGame(game)"
/>
</div>
</b-card>
</div>
</template>
<script>
@ -71,6 +70,3 @@ export default {
},
};
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
</style>

View file

@ -0,0 +1,45 @@
<template lang="html">
<b-card
no-body
:title="game.name"
:img-src="coverUrl"
:img-alt="game.name"
img-top
class="mb-2"
footer-class="p-0 text-center font-weight-bold bold strong"
@click="addGameToList"
>
<!-- :to="{ name: 'game', params: { id: game.id, slug: game.slug }}" -->
<template #footer>
<small class="text-muted">
<strong>{{ game.name }}</strong>
</small>
</template>
</b-card>
</template>
<script>
import { getGameCoverUrl } from '@/utils';
export default {
props: {
game: {
type: Object,
required: true,
},
},
computed: {
coverUrl() {
return getGameCoverUrl(this.game);
}
},
methods: {
addGameToList() {
this.$bus.$emit('ADD_GAME', this.game.id);
},
},
};
</script>

View file

@ -1,27 +0,0 @@
<template lang="html">
<div>
<auth-modal />
<keyboard-shortcuts-modal />
<add-remove-game />
</div>
</template>
<script>
import { mapState } from 'vuex';
import AuthModal from '@/components/AuthModal';
import AddRemoveGame from '@/components/AddRemoveGame';
import KeyboardShortcutsModal from '@/components/KeyboardShortcutsModal';
export default {
components: {
AuthModal,
AddRemoveGame,
KeyboardShortcutsModal,
},
computed: {
...mapState(['user']),
},
};
</script>

View file

@ -17,8 +17,8 @@
<b-button
block
size="sm"
variant="outline-light"
class="text-dark d-flex justify-content-between align-items-center px-2"
variant="transparent"
class="text-dark d-flex justify-content-between align-items-center pl-0"
:disabled="preview || (user && user.uid !== board.owner)"
:to="{ name: 'board.list.edit', params: { id: board.id, listIndex } }"
>

View file

@ -1,8 +1,8 @@
<template lang="html">
<header class="py-1 px-2 d-flex">
<header class="py-1 px-2 d-flex position-fixed">
<home-button />
<boards-dropdown v-if="isBoardPage || isGamePage" />
<game-dropdown v-if="isGamePage" />
<boards-dropdown v-if="board.id && (isBoardPage || isGamePage)" />
<!-- <game-dropdown v-if="isGamePage" /> -->
<div class="global-actions">
<portal-target name="headerActions" />
@ -11,7 +11,12 @@
Upgrade
</b-button> -->
<search-box />
<b-button
variant="primary"
:to="{ name: 'search' }"
>
<i class="fas fa-search fa-fw" aria-hidden />
</b-button>
<b-dropdown
v-if="user"
@ -24,6 +29,7 @@
<template #button-content>
<b-avatar rounded variant="info" :src="user.photoURL" />
</template>
<b-dropdown-item
:to="{ name: 'settings' }"
>
@ -58,9 +64,8 @@
</template>
<script>
import GameDropdown from '@/components/Game/GameDropdown';
// import GameDropdown from '@/components/Game/GameDropdown';
import BoardsDropdown from '@/components/BoardsDropdown';
import SearchBox from '@/components/SearchBox';
import HomeButton from '@/components/Shared/HomeButton';
import sessionMixin from '@/mixins/sessionMixin';
import { mapState } from 'vuex';
@ -69,9 +74,8 @@ export default {
mixins: [sessionMixin],
components: {
GameDropdown,
// GameDropdown,
BoardsDropdown,
SearchBox,
HomeButton,
},
@ -101,6 +105,7 @@ export default {
// height: 46px;
grid-template-columns: 65px 1fr;
// background-color: #574c4f;
z-index: 1;
}
.toolbar {

View file

@ -1,6 +1,6 @@
<template lang="html">
<div class="search-box mr-2">
<b-form @submit.prevent="search" :class="isSearchPage ? '' : 'd-none d-md-block'">
<div class="search-box">
<b-form @submit.prevent="search">
<b-input-group>
<b-form-input
v-model="searchText"
@ -16,13 +16,20 @@
type="submit"
variant="info"
>
<i class="fas fa-search fa-fw" aria-hidden />
<i
class="fas fa-search fa-fw"
aria-hidden
/>
</b-button>
</b-input-group-append>
</b-input-group>
</b-form>
<b-button :class="isSearchPage ? 'd-none' : 'd-md-none'" variant="primary" :to="{ name: 'search' }">
<b-button
:class="isSearchPage ? 'd-none' : 'd-md-none'"
variant="primary"
:to="{ name: 'search' }"
>
<i class="fas fa-search fa-fw" aria-hidden />
</b-button>
</div>

View file

@ -36,6 +36,10 @@ export default {
return this.list?.settings?.showGameTags && this.gameTags;
},
showReleaseDates() {
return this.list?.settings?.showReleaseDates;
},
gameProgress() {
const { gameId, progresses } = this;

View file

@ -1,6 +1,6 @@
<template lang="html">
<div
:class="['board p-3', { dragging, empty }]"
:class="['board px-3 pb-3', { dragging, empty }]"
:style="boardStyles"
>
<board-placeholder v-if="loading" />
@ -16,19 +16,7 @@
<empty-board v-if="empty" />
<div
v-else-if="user && user.uid && user.uid === board.owner"
class="d-flex flex-column"
>
<b-button
variant="light"
v-b-modal:add-list
>
<i class="fas fa-plus fa-fw" aria-hidden />
</b-button>
</div>
<add-list-modal />
<add-list v-else-if="user && user.uid && user.uid === board.owner" />
</template>
<b-alert
@ -44,7 +32,7 @@
<script>
import BoardPlaceholder from '@/components/Board/BoardPlaceholder';
import EmptyBoard from '@/components/Board/EmptyBoard';
import AddListModal from '@/components/Board/AddListModal';
import AddList from '@/components/Board/AddList';
import GameList from '@/components/Lists/GameList';
import chunk from 'lodash.chunk';
import { mapState, mapGetters } from 'vuex';
@ -54,7 +42,7 @@ export default {
GameList,
BoardPlaceholder,
EmptyBoard,
AddListModal,
AddList,
},
data() {
@ -188,7 +176,7 @@ export default {
const { lists } = this.board;
if (lists && lists.length === 0) {
this.$bvModal.show('add-list');
// TODO: toggle add list
}
const boardGames = lists.length

View file

@ -23,170 +23,153 @@
</header>
<form ref="boardSettingsForm" @submit.stop.prevent="submit">
<b-row>
<b-col>
<b-button @click="goToBoard">
Back to board
</b-button>
<b-form-group
:label="$t('board.settings.nameLabel')"
label-for="name"
>
<b-form-input
id="name"
v-model="name"
required
/>
</b-form-group>
<b-form-group
:label="$t('board.settings.nameLabel')"
label-for="name"
>
<b-form-input
id="name"
v-model="name"
required
/>
</b-form-group>
<b-form-group
:label="$t('board.settings.descriptionLabel')"
label-for="description"
>
<b-form-textarea
id="description"
v-model="description"
maxlength="280"
rows="3"
/>
</b-form-group>
<b-form-group
:label="$t('board.settings.descriptionLabel')"
label-for="description"
>
<b-form-textarea
id="description"
v-model="description"
maxlength="280"
rows="3"
/>
</b-form-group>
<b-form-checkbox v-model="isPublic" switch class="mb-2">
Make board public (beta)
</b-form-checkbox>
<b-form-checkbox v-model="isPublic" switch class="mb-2">
Make board public (beta)
</b-form-checkbox>
<b-alert show variant="info" v-if="isPublic" class="m-0">
<strong>Public Board URL</strong>
<br>
<small>{{ `https://app.gamebrary.com/#/b/${board.id}` }}</small>
</b-alert>
<b-alert show variant="info" v-if="isPublic" class="m-0">
<strong>Public Board URL</strong>
<br>
<small>{{ `https://app.gamebrary.com/#/b/${board.id}` }}</small>
</b-alert>
<hr class="my-3">
<hr class="my-3">
<edit-board-background-modal />
<hr class="my-3">
<b-button v-b-modal.boardBackground>
<i class="fas fa-images fa-fw" aria-hidden />
<br />
Change background
</b-button>
<b-button
variant="danger"
@click="confirmDelete"
>
{{ $t('board.settings.deleteBoard') }}
</b-button>
<hr class="my-3">
<b-button
variant="primary"
:disabled="saving"
@click="saveSettings"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button>
</b-col>
<b-button
variant="danger"
@click="confirmDelete"
>
{{ $t('board.settings.deleteBoard') }}
</b-button>
<b-col>
<!-- <b-button
variant="primary"
:disabled="saving"
@click="saveSettings"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button> -->
<!-- <b-button
variant="primary"
:disabled="saving"
@click="saveSettings"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button> -->
<b-alert :show="noPlatformsSelected" variant="warning">
No platforms selected, game search will include all platforms.
</b-alert>
<!-- <b-alert :show="noPlatformsSelected" variant="warning">
No platforms selected, game search will include all platforms.
</b-alert>
<b-alert :show="noPlatformsSelected" variant="success">
Select platforms to limit search results.
</b-alert>
<b-alert :show="noPlatformsSelected" variant="success">
Select platforms to limit search results.
</b-alert> -->
<!-- <platform-picker v-model="platforms" /> -->
<!-- <b-button-toolbar aria-label="Toolbar with button groups and dropdown menu">
<b-button-group class="mx-1">
<b-button>New</b-button>
<b-button>Edit</b-button>
<b-button>Undo</b-button>
</b-button-group>
<b-dropdown class="mx-1" right text="menu">
<b-dropdown-item>Item 1</b-dropdown-item>
<b-dropdown-item>Item 2</b-dropdown-item>
<b-dropdown-item>Item 3</b-dropdown-item>
</b-dropdown>
<b-button-group class="mx-1">
<b-button>Save</b-button>
<b-button>Cancel</b-button>
</b-button-group>
</b-button-toolbar> -->
<!-- <platform-picker v-model="platforms" /> -->
<!-- <b-button-toolbar aria-label="Toolbar with button groups and dropdown menu">
<b-button-group class="mx-1">
<b-button>New</b-button>
<b-button>Edit</b-button>
<b-button>Undo</b-button>
</b-button-group>
<b-dropdown class="mx-1" right text="menu">
<b-dropdown-item>Item 1</b-dropdown-item>
<b-dropdown-item>Item 2</b-dropdown-item>
<b-dropdown-item>Item 3</b-dropdown-item>
</b-dropdown>
<b-button-group class="mx-1">
<b-button>Save</b-button>
<b-button>Cancel</b-button>
</b-button-group>
</b-button-toolbar> -->
<!-- <div class="d-flex mb-2">
<div class="filter mr-2">
<small class="d-block text-muted">Show:</small>
<b-button size="sm">All</b-button>
<b-button size="sm">Consoles</b-button>
<b-button size="sm">Handhelds</b-button>
<b-button size="sm">PC</b-button>
</div>
<!-- <div class="d-flex mb-2">
<div class="filter mr-2">
<small class="d-block text-muted">Show:</small>
<b-button size="sm">All</b-button>
<b-button size="sm">Consoles</b-button>
<b-button size="sm">Handhelds</b-button>
<b-button size="sm">PC</b-button>
</div>
<div class="sort">
<small class="d-block text-muted">Sort by:</small>
<b-button size="sm">All</b-button>
<b-button size="sm">All</b-button>
<b-button size="sm">All</b-button>
</div>
</div> -->
<!-- <b-form-group
label="Stacked (vertical) switch style checkboxes"
v-slot="{ ariaDescribedby }"
>
<b-form-checkbox-group
v-model="selected"
:options="options"
:aria-describedby="ariaDescribedby"
switches
stacked
/>
</b-form-group> -->
<div class="sort">
<small class="d-block text-muted">Sort by:</small>
<b-button size="sm">All</b-button>
<b-button size="sm">All</b-button>
<b-button size="sm">All</b-button>
</div>
</div> -->
<!-- <b-form-group
label="Stacked (vertical) switch style checkboxes"
v-slot="{ ariaDescribedby }"
>
<b-form-checkbox-group
v-model="selected"
:options="options"
:aria-describedby="ariaDescribedby"
switches
stacked
/>
</b-form-group> -->
<b-dropdown
text="Select platforms"
class="platforms-dropdown"
>
<b-dropdown-item
v-for="platform in platforms"
:key="platform.id"
>
{{ platform.name }}
</b-dropdown-item>
<!-- <pre>{{ platforms }}</pre> -->
<!-- <b-dropdown-item>Second Action</b-dropdown-item> -->
<!-- <b-dropdown-item>Third Action</b-dropdown-item> -->
<!-- <b-dropdown-divider></b-dropdown-divider> -->
<!-- <b-dropdown-item active>Active action</b-dropdown-item> -->
<!-- <b-dropdown-item disabled>Disabled action</b-dropdown-item> -->
</b-dropdown>
<!-- <b-dropdown
text="Select platforms"
class="platforms-dropdown"
>
<b-dropdown-item
v-for="platform in platforms"
:key="platform.id"
>
{{ platform.name }}
</b-dropdown-item>
</b-dropdown> -->
<!-- <b-button
v-for="platform in sortedPlatforms"
:variant="value.includes(platform.id) ? 'primary' : 'dark'"
:key="platform.id"
>
<small :class="value.includes(platform.id) ? '' : 'text-muted'">
{{ platform.name }}
</small>
</b-button> -->
</b-col>
<!-- <b-button
v-for="platform in sortedPlatforms"
:variant="value.includes(platform.id) ? 'primary' : 'dark'"
:key="platform.id"
>
<small :class="value.includes(platform.id) ? '' : 'text-muted'">
{{ platform.name }}
</small>
</b-button> -->
<b-col>
<edit-board-background-modal />
<b-button v-b-modal.boardBackground>
<i class="fas fa-images fa-fw" aria-hidden />
<br />
Change background
</b-button>
</b-col>
</b-row>
<b-button
variant="primary"
:disabled="saving"
@click="saveSettings"
>
<b-spinner small v-if="saving" />
<span v-else>{{ $t('global.save') }}</span>
</b-button>
</form>
</b-card>
</b-col>

View file

@ -6,11 +6,28 @@
<!-- TODO: Show lists/boards that the game belongs to -->
<template lang="html">
<b-container fluid class="p-2">
<b-container fluid class="game-page p-2">
<b-skeleton v-if="loading" />
<template v-else-if="game">
<b-row>
<b-row class="game-backdrop" :style="`background-image: url(${gameScrenshot})`">
<b-col
cols="12"
>
<div class="vh-100">
<!-- <b-img
:src="gameCoverUrl"
:alt="game.name"
class="cursor-pointer game-cover"
width="200"
rounded
@click.stop="openGameCover"
/> -->
</div>
</b-col>
</b-row>
<b-row class="game">
<b-col
offset="2"
offset-sm="0"
@ -46,6 +63,7 @@
md="8"
lg="8"
xl="9"
class="bg-white rounded p-5"
>
<b-row>
<b-col
@ -127,9 +145,6 @@
<b-col
cols="12"
sm="12"
md="6"
xl="6"
class="mt-3"
>
<similar-games
@ -144,21 +159,21 @@
xl="6"
class="mt-3"
>
<game-speedruns v-if="game" />
<!-- <game-speedruns v-if="game" /> -->
<!-- <pre>{{ game.speedruns }}</pre> -->
<!-- TODO: add bundles to game detail? -->
</b-col>
<b-col
<!-- <b-col
cols="12"
class="mt-3"
>
<b-card>
<h4>[BUNDLES]</h4>
</b-card>
<!-- <pre>{{ game }}</pre> -->
<!-- {{ game.bundles ? `Found in ${game.bundles.length} compilations.` : null }} -->
</b-col>
<pre>{{ game }}</pre>
{{ game.bundles ? `Found in ${game.bundles.length} compilations.` : null }}
</b-col> -->
</b-row>
</template>
@ -248,8 +263,6 @@
>
loading...
</timeline> -->
<!-- <div class="game-backdrop" :style="`background-image: url(${gameScrenshot})`" /> -->
</b-container>
</template>
@ -265,7 +278,7 @@ import GameRating from '@/components/Game/GameRating';
import GameDescription from '@/components/Game/GameDescription';
import SimilarGames from '@/components/Game/SimilarGames';
import GameWebsites from '@/components/Game/GameWebsites';
import GameSpeedruns from '@/components/Game/GameSpeedruns';
// import GameSpeedruns from '@/components/Game/GameSpeedruns';
export default {
components: {
@ -277,7 +290,7 @@ export default {
GameRating,
GameNotes,
GameWebsites,
GameSpeedruns,
// GameSpeedruns,
SimilarGames,
},
@ -360,7 +373,7 @@ export default {
watch: {
gameId(gameId) {
document.getElementsByTagName('main')[0].scrollTop = 0;
// document.getElementsByTagName('main')[0].scrollTop = 0;
if (gameId) this.loadGame();
// TODO: handle missing id, redirect? 404? search?
@ -469,15 +482,17 @@ export default {
</script>
<style lang="scss" rel="stylesheet/scss" scoped>
// .game-page {
// // z-index: 0;
// }
.game {
margin-top: -50vh;
}
.game-backdrop {
width: 100%;
height: 100vw;
// position: fixed;
// top: 0;
backdrop-filter: grayscale(0.5) opacity(0.8) /* ...and on and on... */;
background-repeat: no-repeat;
background-size: contain;
// opacity: 0.1;
z-index: 0;
}
</style>

View file

@ -1,26 +1,29 @@
<template lang="html">
<b-container>
<b-row>
<b-col cols="3">
<!-- TODO: add filters -->
<!-- TODO: add view toggle -->
Filter
<b-col cols="3" class="position-sticky mt-2">
<b-card>
test
<!-- TODO: add filters -->
<!-- TODO: add view toggle -->
Filter
<h3>Sort by</h3>
Latest
Oldest
Relevance
<h3>Sort by</h3>
Latest
Oldest
Relevance
<h3>Filters</h3>
Tags
Genre
Platform
Year released
<h3>Filters</h3>
Tags
Genre
Platform
Year released
</b-card>
</b-col>
<b-col cols="9">
<div class="search-page bg-white p-2">
<div class="search-page p-2">
<search-box />
<!-- <b-alert show variant="success">
Custom search controls go here!
</b-alert> -->
@ -30,13 +33,38 @@
<b-skeleton v-if="loading" />
<div v-else-if="searchResults.length > 0">
<h3>Search results</h3>
<header class="my-2 d-flex align-items-center justify-content-between">
<h3>Search results</h3>
<game-card-search
v-for="game in searchResults"
:key="game.id"
:game="game"
/>
<b-button-toolbar key-nav aria-label="Toolbar with button groups">
<b-button-group class="mx-1">
<b-button :variant="listView ? 'primary' : 'secondary'" @click="listView = true">
<i class="fa-solid fa-list fa-fw" aria-hidden />
</b-button>
<b-button :variant="listView ? 'secondary' : 'primary'" @click="listView = false">
<i class="fa-solid fa-grip fa-fw" aria-hidden />
</b-button>
</b-button-group>
</b-button-toolbar>
</header>
<template v-if="listView">
<game-card-search
v-for="game in searchResults"
:key="game.id"
:game="game"
/>
</template>
<div v-else class="masonry-container">
<game-card-search-vertical
v-for="game in searchResults"
class="masonry-item"
:key="game.id"
:game="game"
/>
</div>
</div>
<b-container v-else-if="query.length > 0">
@ -56,16 +84,21 @@
<script>
import GameCardSearch from '@/components/GameCards/GameCardSearch';
import SearchBox from '@/components/SearchBox';
import GameCardSearchVertical from '@/components/GameCards/GameCardSearchVertical';
export default {
components: {
GameCardSearch,
SearchBox,
GameCardSearchVertical,
},
data() {
return {
searchResults: [],
loading: false,
listView: true,
};
},
@ -104,4 +137,14 @@ export default {
.search-page {
min-height: calc(100vh - 46px);
}
.masonry-container {
column-count: 5;
column-gap: 1rem;
}
.masonry-item {
display: inline-block;
width: 100%;
}
</style>