Improve game highlighting

This commit is contained in:
gamebrary 2024-09-05 15:53:49 -07:00
parent af3f161022
commit 02d5836ae1
17 changed files with 123 additions and 49 deletions

View file

@ -19,6 +19,7 @@
import { mapState, mapGetters } from 'vuex';
import AddKanbanList from '@/components/Board/AddKanbanList';
import KanbanList from '@/components/Lists/KanbanList';
import { HIGHLIGHTED_GAME_TIMEOUT } from '@/constants'
export default {
components: {
@ -27,7 +28,7 @@ export default {
},
mounted() {
if (this.highlightedGame) this.highlightGame();
if (this.highlightedGame) this.scrollToGame();
},
computed: {
@ -40,7 +41,7 @@ export default {
},
methods: {
highlightGame() {
scrollToGame() {
const lists = Object.values(this.$refs);
lists.forEach(([list], index) => {
@ -55,7 +56,7 @@ export default {
setTimeout(() => {
this.$store.commit('SET_HIGHLIGHTED_GAME', null);
}, 5000);
}, HIGHLIGHTED_GAME_TIMEOUT);
},
},
};

View file

@ -1,3 +1,4 @@
<!-- <router-link :to="{ name: 'board', params: { id: board.id } }"></router-link> -->
<!-- TODO: make mini boards links so you can cmd click them -->
<template lang="html">
<b-card
@ -33,7 +34,6 @@
<component
:is="miniBoardComponent"
:board="formattedBoard"
:gameId="gameId"
/>
</div>
</b-card>
@ -50,7 +50,6 @@ import TierMiniBoard from '@/components/MiniBoards/TierMiniBoard';
export default {
props: {
board: Object,
gameId: Number,
thumbnail: Boolean,
},
@ -73,7 +72,7 @@ export default {
},
computed: {
...mapState(['cachedGames']),
...mapState(['cachedGames', 'game']),
...mapGetters(['darkTheme']),
miniBoardComponent() {

View file

@ -2,6 +2,7 @@
<div class="standard-board pb-5">
<StandardList
v-for="(list, listIndex) in board.lists"
:ref="`list-${listIndex}`"
:key="list.id"
:listIndex="listIndex"
:list="list"
@ -12,14 +13,14 @@
<script>
import { mapState } from 'vuex';
import StandardList from '@/components/Lists/StandardList';
import { HIGHLIGHTED_GAME_TIMEOUT } from '@/constants';
export default {
components: {
StandardList,
},
computed: {
...mapState(['board']),
...mapState(['board', 'highlightedGame']),
list() {
const [firstList] = this.board?.lists;
@ -38,9 +39,30 @@ export default {
mounted() {
if (this.needsFlattening) this.flattenAndSaveBoard();
if (this.highlightedGame) this.highlightGame();
},
methods: {
highlightGame() {
const lists = Object.values(this.$refs);
lists.forEach(([list], index) => {
const [gameRef] = list.$refs[`${index}-${this.highlightedGame}`];
if (gameRef) {
console.log('gameRef', gameRef);
setTimeout(() => {
gameRef?.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, index * 1000);
}
});
setTimeout(() => {
this.$store.commit('SET_HIGHLIGHTED_GAME', null);
}, HIGHLIGHTED_GAME_TIMEOUT);
},
async flattenAndSaveBoard() {
const mergedGamesList = [...new Set(this.board?.lists?.map(({ games }) => games)?.flat())];

View file

@ -7,6 +7,7 @@
<TierList
v-for="(list, listIndex) in board.lists"
:list="list"
:ref="`tier-${listIndex}`"
:allGames="allGames"
:listIndex="listIndex"
:key="listIndex"
@ -20,6 +21,7 @@
import { mapState, mapGetters } from 'vuex';
import AddTier from '@/components/Board/AddTier';
import TierList from '@/components/Lists/TierList';
import { HIGHLIGHTED_GAME_TIMEOUT } from '@/constants';
export default {
components: {
@ -27,8 +29,12 @@ export default {
AddTier,
},
mounted() {
if (this.highlightedGame) this.highlightGame();
},
computed: {
...mapState(['board']),
...mapState(['board', 'highlightedGame']),
...mapGetters(['isBoardOwner', 'darkTheme']),
allGames() {
@ -41,6 +47,24 @@ export default {
},
methods: {
highlightGame() {
const lists = Object.values(this.$refs);
lists.forEach(([list], index) => {
const [gameRef] = list.$refs[`${index}-${this.highlightedGame}`];
if (gameRef) {
setTimeout(() => {
gameRef?.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, index * 1000);
}
});
setTimeout(() => {
this.$store.commit('SET_HIGHLIGHTED_GAME', null);
}, HIGHLIGHTED_GAME_TIMEOUT);
},
async selectGame(gameId) {
const board = JSON.parse(JSON.stringify(this.board));

View file

@ -7,7 +7,6 @@
v-for="board in boardsWithGame"
:key="board.id"
:board="board"
:gameId="game.id"
class="mb-3"
@click.native="handleBoardClick(board.id)"
/>

View file

@ -7,6 +7,7 @@
vertical,
small,
slim,
highlighted: highlightedGame === gameId,
'semi-transparent': transparencyEnabled,
},
darkTheme ? 'dark text-light' : 'light',
@ -155,7 +156,7 @@ export default {
},
computed: {
...mapState(['settings', 'cachedGames', 'tags', 'notes', 'progresses', 'board', 'games', 'user']),
...mapState(['settings', 'cachedGames', 'tags', 'notes', 'progresses', 'board', 'games', 'user', 'highlightedGame']),
...mapGetters(['isRTL', 'darkTheme', 'transparencyEnabled']),
game() {
@ -226,6 +227,10 @@ export default {
transition: background-color 300ms linear;
padding: 0.5rem;
&.highlighted {
border: 3px dotted var(--danger);
}
&.slim {
padding: 0;
grid-gap: 0;

View file

@ -93,7 +93,6 @@
:small="list.smallCover"
:hide-cover="list.hideCover"
:hide-title="list.hideTitle"
:class="{ 'highlighted': highlightedGame == gameId }"
@click.native="openGame(gameId, list)"
/>
</draggable>
@ -118,7 +117,13 @@ import draggable from 'vuedraggable';
import GameCard from '@/components/GameCard';
import slugify from 'slugify'
import orderby from 'lodash.orderby';
import { SORT_TYPE_ALPHABETICALLY, SORT_TYPE_RATING, SORT_TYPE_PROGRESS } from '@/constants';
import {
SORT_TYPE_ALPHABETICALLY,
SORT_TYPE_RATING,
SORT_TYPE_PROGRESS,
HIGHLIGHTED_GAME_TIMEOUT
} from '@/constants';
import { mapState, mapGetters } from 'vuex';
export default {
@ -154,14 +159,14 @@ export default {
},
computed: {
...mapState(['cachedGames', 'dragging', 'progresses', 'board', 'user', 'settings', 'highlightedGame']),
...mapState(['cachedGames', 'dragging', 'progresses', 'board', 'user', 'settings']),
...mapGetters(['isBoardOwner', 'darkTheme', 'transparencyEnabled']),
sortMessage() {
if (this.sortBy === SORT_TYPE_ALPHABETICALLY) return 'List sorted alphabetically'
if (this.sortBy === SORT_TYPE_RATING) return 'List sorted by rating'
if (this.sortBy === SORT_TYPE_PROGRESS) return 'List sorted by progress'
return null;
},
@ -265,7 +270,7 @@ export default {
setTimeout(() => {
this.$store.commit('SET_HIGHLIGHTED_GAME', null);
}, 5000);
}, HIGHLIGHTED_GAME_TIMEOUT);
}
},
@ -377,10 +382,6 @@ export default {
.list-settings {
padding: 1rem;
}
.highlighted {
outline: 3px dashed var(--primary);
}
</style>
<style lang="scss" rel="stylesheet/scss">

View file

@ -25,6 +25,7 @@
v-for="(game, index) in listGames"
:key="index"
:list="list"
:ref="`${listIndex}-${game.id}`"
:game-id="game.id"
:ranked="board.ranked"
:rank="index + 1"

View file

@ -64,11 +64,12 @@
:group="{ name: 'games' }"
@end="dragEnd"
@start="dragStart"
>
>
<GameCard
v-for="gameId in list.games"
:key="gameId"
:game-id="gameId"
:ref="`${listIndex}-${gameId}`"
hide-title
hide-tags
hide-notes

View file

@ -12,10 +12,14 @@
<div
v-for="(game, index) in list.games"
:key="index"
style="width: 60px"
style="width: 60px;"
class="p-1 d-flex"
:class="[
gameId && game.id === gameId ? 'bg-danger' : darkTheme ? 'border-black bg-dark' : 'border-light bg-white',
game.id === currentGameId
? 'bg-danger'
: darkTheme
? 'border-black bg-dark'
: 'border-light bg-white',
{
'border-bottom' : index !== list.games.length - 1,
}
@ -24,7 +28,7 @@
<b-avatar
style="border-radius: 4px !important"
text=" "
:src="gameId && game.src && game.id === gameId ? game.src : showGameThumbnails && game.src ? game.src : null"
:src="currentGameId && game.src && game.id === currentGameId ? game.src : showGameThumbnails && game.src ? game.src : null"
v-b-tooltip.hover
:variant="darkTheme ? 'black' : 'light'"
size="24"
@ -36,30 +40,23 @@
<div
v-else
class="rounded overflow-hidden"
style="height: 22px; width: 60px;"
style="height: 28px; width: 60px;"
/>
</b-card>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters, mapState } from 'vuex';
export default {
props: {
gameId: Number,
board: {
type: Object,
required: true,
},
},
data() {
return {
// Your data properties here
};
},
methods: {
highlightGame(gameId) {
this.$store.commit('SET_HIGHLIGHTED_GAME', gameId);
@ -68,14 +65,13 @@ export default {
computed: {
...mapGetters(['darkTheme', 'showGameThumbnails']),
},
...mapState(['game', 'routeName']),
mounted() {
// Code to run when the component is mounted
currentGameId() {
return this.routeName === 'game'
? this.game?.id
: null;
},
},
};
</script>
<style scoped>
/* Your CSS styles here */
</style>

View file

@ -27,7 +27,14 @@
<div
v-for="(game, index) in firstList.games"
:key="index"
:class="[darkTheme ? 'border-black bg-dark' : 'border-light bg-white', { 'border-bottom': index !== firstList.games.length - 1 }]"
:class="[
currentGameId == game.id
? 'border bg-danger border-danger'
: darkTheme
? 'border-black bg-dark'
: 'border-light bg-white',
{ 'border-bottom': index !== firstList.games.length - 1 },
]"
class=""
>
<b-avatar
@ -55,7 +62,7 @@
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters, mapState } from 'vuex';
export default {
props: {
@ -63,11 +70,17 @@ export default {
type: Object,
required: true,
},
gameId: Number,
},
computed: {
...mapGetters(['darkTheme', 'showGameThumbnails']),
...mapState(['routeName', 'game']),
currentGameId() {
return this.routeName === 'game'
? this.game?.id
: null;
},
isGrid() {
return this.board?.grid;

View file

@ -1,5 +1,6 @@
<template>
<div>
<pre>{{ currentGameId || 'not game page' }}</pre>
<div
class="d-flex mx-2"
v-for="tier in board.lists"
@ -22,6 +23,7 @@
square
:src="showGameThumbnails ? game.src : null"
style="margin-left: 4px; border-radius: 4px !important;"
:class="currentGameId === game.id ? 'border border-danger' : null"
size="20"
/>
</div>
@ -29,7 +31,7 @@
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters, mapState } from 'vuex';
export default {
props: {
board: {
@ -41,6 +43,13 @@ export default {
computed: {
...mapGetters(['darkTheme', 'showGameThumbnails']),
...mapState(['routeName', 'game']),
currentGameId() {
return this.routeName === 'game'
? this.game?.id
: null;
},
},
methods: {

View file

@ -28,6 +28,7 @@ export const SORT_TYPE_RATING = 'rating';
export const SORT_TYPE_PROGRESS = 'progress';
export const MAX_QUERY_LIMIT = 500;
export const HIGHLIGHTED_GAME_TIMEOUT = 5000; // set back to 5000
export const BOARD_TYPES = [
{ text: 'Kanban', value: BOARD_TYPE_KANBAN },

View file

@ -537,10 +537,12 @@ export default {
},
LOAD_RELEASES({ commit }) {
// TODO: use await async
return new Promise((resolve, reject) => {
axios
.get("https://api.github.com/repos/romancm/gamebrary/releases")
.then(({ data }) => {
console.log('releases', data);
// const [latestRelease] = data;
// const latestReleaseVersion = latestRelease && latestRelease.tag_name;
// const lastReleaseSeenByUser = this.settings?.release || null;

View file

@ -15,8 +15,8 @@ import linkifyHtml from 'linkify-html';
export default {
latestRelease: ({ releases }) => releases?.[0]?.tag_name || 'v1',
darkTheme: ({ route, board, settings }) => {
const boardOverride = route === 'board' && board?.darkTheme;
darkTheme: ({ routeName, board, settings }) => {
const boardOverride = routeName === 'board' && board?.darkTheme;
return settings?.darkTheme || boardOverride || false
},

View file

@ -161,8 +161,8 @@ export default {
Vue.set(state.game, 'news', news);
},
SET_ROUTE(state, route) {
state.route = route;
SET_ROUTE(state, routeName) {
state.routeName = routeName;
},
APPEND_WIKIPEDIA_GAME_DATA(state, data) {

View file

@ -26,5 +26,5 @@ export default {
gameSelectorData: null,
menuOpen: true,
editProfileSidebarOpen: false,
route: {},
routeName: null,
};