Started to refactor notes, added more icons and several UI updates.

This commit is contained in:
gamebrary 2024-03-18 16:31:58 -07:00
parent fdb90a8ef0
commit 70688f447c
32 changed files with 583 additions and 320 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View file

@ -1,3 +1,5 @@
<!-- TODO: add like button to all game covers -->
<!-- TODO: finish notifications -->
<!-- TODO: finish boards transparency -->
<!-- TODO: add itch.io affiliates link -->
<!-- TODO: add features page -->

View file

@ -5,62 +5,62 @@
:variant="isBoardPage ? 'white' : 'transparent'"
v-bind="dockDropdownProps"
>
<template #button-content>
<img
src="/img/dock-icons/boards.png"
alt="wikipedia"
width="24"
/>
</template>
<template #button-content>
<img
src="/img/dock-icons/boards.png"
alt="wikipedia"
width="24"
/>
</template>
<b-dropdown-item
:to="{ name: 'boards' }"
>
<i class="fa-regular fa-rectangle-list fa-fw"></i>
<span class="ml-2">My boards</span>
</b-dropdown-item>
<!-- <b-dropdown-group v-if="user" class="p-1 bg-light m-1 rounded">
<b-dropdown-item
v-for="board in recentlyUpdatedBoards"
:key="board.id"
:to="{ name: 'board', params: { id: board.id } }"
>
<small>{{ board.name }}</small>
</b-dropdown-item>
</b-dropdown-group> -->
<!-- <b-dropdown-item
v-if="isBoardEditPage"
:to="{ name: 'board', params: { id: board.id } }"
>
<i class="fa-solid fa-caret-left"></i>
<span class="ml-2">Back to board</span>
</b-dropdown-item> -->
<b-dropdown-item
v-if="canEdit"
:to="{ name: 'board.edit', params: { id: board.id } }"
>
<i class="fa-solid fa-pen fa-fw" />
<span class="ml-2">Edit board</span>
</b-dropdown-item>
<b-dropdown-item
:to="{ name: 'create.board' }"
>
<i class="fa-regular fa-plus fa-fw" />
<span class="ml-2">Create board</span>
</b-dropdown-item>
<!-- TODO: add logic for this -->
<b-dropdown-item
disabled
>
<i class="fa-solid fa-clone fa-fw"></i>
<span class="ml-2">Copy board</span>
<b-dropdown-item
:to="{ name: 'boards' }"
>
<i class="fa-regular fa-rectangle-list fa-fw"></i>
<span class="ml-2">My boards</span>
</b-dropdown-item>
<!-- <b-dropdown-group v-if="user" class="p-1 bg-light m-1 rounded">
<b-dropdown-item
v-for="board in recentlyUpdatedBoards"
:key="board.id"
:to="{ name: 'board', params: { id: board.id } }"
>
<small>{{ board.name }}</small>
</b-dropdown-item>
</b-dropdown-group> -->
<!-- <b-dropdown-item
v-if="isBoardEditPage"
:to="{ name: 'board', params: { id: board.id } }"
>
<i class="fa-solid fa-caret-left"></i>
<span class="ml-2">Back to board</span>
</b-dropdown-item> -->
<b-dropdown-item
v-if="canEdit"
:to="{ name: 'board.edit', params: { id: board.id } }"
>
<i class="fa-solid fa-pen fa-fw" />
<span class="ml-2">Edit board</span>
</b-dropdown-item>
<b-dropdown-item
:to="{ name: 'create.board' }"
>
<i class="fa-regular fa-plus fa-fw" />
<span class="ml-2">Create board</span>
</b-dropdown-item>
<!-- TODO: add logic for this -->
<!-- <b-dropdown-item
disabled
>
<i class="fa-solid fa-clone fa-fw"></i>
<span class="ml-2">Copy board</span>
</b-dropdown-item> -->
<b-dropdown-divider />
<b-dropdown-item

View file

@ -20,14 +20,14 @@
<b-dropdown-group v-if="isGamePage" class="p-1 bg-light m-1 rounded">
<!-- TODO: style this better -->
<b-img
v-if="isGamePage && !isVerticalNav"
v-if="isGamePage && !isVerticalNav && gameName"
:src="$options.getImageUrl(game)"
:alt="game.name"
:alt="gameName"
height="32"
style="border-radius: 3px;"
/>
{{ game.name }}
<span>{{ gameName }}</span>
<b-dropdown-item-button @click="$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug } })">
Add note
@ -80,8 +80,12 @@ export default {
return ['game.notes','game','game.news'].includes(this.$route.name);
},
gameName() {
return this.game?.name;
},
gameButtonTitle() {
if (this.isGamePage) return this.game.name;
if (this.isGamePage) return this.game?.name;
return 'Games';
}

View file

@ -0,0 +1,54 @@
<template>
<b-dropdown
v-if="user"
v-b-tooltip.hover.auto="{ delay: { show: 500, hide: 50 } }"
title="Notes"
v-bind="dockDropdownProps"
>
<template #button-content>
<img
src="/img/dock-icons/notes.png"
alt="wikipedia"
width="24"
/>
</template>
<b-dropdown-item
:to="{ name: 'create.note' }"
>
<img
src="/img/dock-icons/new-note.png"
alt="Wallpapers"
width="24"
/>
<span class="ml-2">New note</span>
</b-dropdown-item>
<b-dropdown-item :to="{ name: 'notes' }">
<i class="fa-regular fa-rectangle-list fa-fw"></i>
<span class="ml-2">My notes</span>
</b-dropdown-item>
</b-dropdown>
</template>
<script>
import { mapState, mapGetters } from 'vuex'
import { getImageUrl } from '@/utils';
export default {
getImageUrl,
data() {
return {
};
},
computed: {
...mapState(['user']),
...mapGetters(['dockDropdownProps']),
},
};
</script>
<style scoped></style>

View file

@ -44,29 +44,7 @@
<BoardsDockDropdown v-if="user" />
<GamesDockDropdown v-if="user" />
<TagsDockDropdown v-if="user" />
<b-dropdown
v-if="user"
v-b-tooltip.hover.auto="{ delay: { show: 500, hide: 50 } }"
title="Notes"
v-bind="dockDropdownProps"
>
<template #button-content>
<img
src="/img/dock-icons/notes.png"
alt="wikipedia"
width="24"
/>
</template>
<b-dropdown-item
:to="{ name: 'notes' }"
>
<i class="fa-regular fa-rectangle-list fa-fw"></i>
<span class="ml-2">My notes</span>
</b-dropdown-item>
</b-dropdown>
<NotesDockDropdown v-if="user" />
<b-dropdown
v-if="user"
@ -76,16 +54,20 @@
>
<template #button-content>
<img
src="/img/dock-icons/wallpapers.png"
alt="wikipedia"
width="24"
/>
src="/img/dock-icons/wallpapers.png"
alt="Wallpapers"
width="24"
/>
</template>
<b-dropdown-item
:to="{ name: 'wallpapers' }"
>
<i class="fa-regular fa-rectangle-list fa-fw"></i>
<img
src="/img/dock-icons/my-wallpapers.png"
alt="Wallpapers"
width="24"
/>
<span class="ml-2">My wallpapers</span>
</b-dropdown-item>
@ -93,24 +75,31 @@
</b-dropdown>
<SettingsDockDropdown v-if="user" />
<ProfileDockDropdown v-if="user" />
<div v-else class="ml-auto d-flex align-items">
<div class="ml-auto d-flex align-items">
<b-button
v-bind="dockDropdownProps"
:to="{ name: 'search' }"
v-b-tooltip.hover.auto="{ delay: { show: 500, hide: 50 } }"
title="Search"
>
<i class="fa fa-search fa-fw" aria-hidden="true" />
<!-- <i class="fa fa-search fa-fw" aria-hidden="true" /> -->
<img
src="/img/dock-icons/search.png"
alt="wikipedia"
width="24"
/>
</b-button>
<ProfileDockDropdown v-if="user" />
<b-button
variant="danger"
class="ml-2"
:to="{ name: 'auth' }"
>
Get started <span class="d-none d-sm-inline"> it's free!</span>
v-else
variant="danger"
class="ml-2"
:to="{ name: 'auth' }"
>
Get started <span class="d-none d-sm-inline"> it's free!</span>
</b-button>
</div>
</div>
@ -118,13 +107,13 @@
<script>
import { mapState, mapGetters } from 'vuex';
import { getImageUrl } from '@/utils';
import { STATUS_VARIANTS } from '@/constants';
// import { STATUS_VARIANTS } from '@/constants';
import UploadWallpaperButton from '@/components/UploadWallpaperButton';
import BoardsDockDropdown from '@/components/Dock/BoardsDockDropdown';
import ProfileDockDropdown from '@/components/Dock/ProfileDockDropdown';
import SettingsDockDropdown from '@/components/Dock/SettingsDockDropdown';
import TagsDockDropdown from '@/components/Dock/TagsDockDropdown';
import NotesDockDropdown from '@/components/Dock/NotesDockDropdown';
import GamesDockDropdown from '@/components/Dock/GamesDockDropdown';
export default {
@ -135,6 +124,7 @@ export default {
ProfileDockDropdown,
SettingsDockDropdown,
TagsDockDropdown,
NotesDockDropdown,
GamesDockDropdown,
},

View file

@ -35,11 +35,15 @@
</b-form-checkbox>
</b-dropdown-form>
<b-form-select
:value="navPosition"
:options="options"
@change="setNavPosition"
/>
<div class="p-1">
<span>Menu position</span>
<b-form-select
:value="navPosition"
:options="options"
@change="setNavPosition"
/>
</div>
<b-dropdown-item
:to="{ name: 'settings' }"
@ -52,12 +56,19 @@
href="https://github.com/romancm/gamebrary/"
target="_blank"
>
<i class="fa-brands fa-github fa-fw"></i>
<b-img
src="/img/dock-icons/github.png"
width="24"
/>
GitHub
</b-dropdown-item>
<b-dropdown-item v-b-modal.keyboard-shortcuts>
<i class="fa-solid fa-keyboard fa-fw" />
<b-img
src="/img/dock-icons/shortcuts.png"
width="24"
/>
<span class="ml-2">Keyboard Shortcuts</span>
</b-dropdown-item>
@ -65,22 +76,27 @@
:to="{ name: 'help' }"
id="help"
>
<i class="fa-regular fa-circle-question fa-fw" aria-hidden="true" />
<b-img
src="/img/dock-icons/help.png"
width="24"
/>
<span class="ml-2">Help</span>
</b-dropdown-item>
<b-dropdown-item disabled>
<!-- TODO: add i18n -->
<!-- <b-dropdown-item disabled>
<i class="fa-solid fa-language" />
<span class="ml-2">Change language</span>
</b-dropdown-item>
</b-dropdown-item> -->
<b-dropdown-item
<!-- TODO: finish steam integration -->
<!-- <b-dropdown-item
:to="{ name: 'steam.settings' }"
disabled
>
<i class="fab fa-steam fa-fe" aria-hidden />
<span class="ml-2">Steam</span>
</b-dropdown-item>
</b-dropdown-item> -->
</b-dropdown>
</template>

View file

@ -2,6 +2,18 @@
<template>
<div>
<div class="position-relative">
<!-- TODO: put like button in component, pass gameId -->
<!-- TODO: if liked, show dropdown when clicked, options: remove from your games -->
<b-button
variant="transparent"
squared
class="ml-2 mt-1 p-0 position-absolute"
:disabled="!user"
@click="$bus.$emit('SELECT_GAME', gameId)"
>
<i :class="[isLiked ? 'fa-solid': 'fa-regular' , 'fa-heart text-danger']" />
</b-button>
<GameRatings class="position-absolute d-flex" style="bottom: 1rem; right: 1rem;" />
<b-img
@ -36,9 +48,17 @@ export default {
},
computed: {
...mapState(['game', 'cachedGames', 'games']),
...mapState(['game', 'cachedGames', 'games', 'user']),
...mapGetters(['darkTheme', 'gameNews', 'gameLinks', 'gameGenres']),
gameId() {
return this.$route.params.id;
},
isLiked() {
return this.games?.[this.gameId];
},
cachedGame() {
return this.cachedGames?.[Number(this.$route.params.id)] || this.game;
},

View file

@ -1,5 +1,5 @@
<template lang="html">
<header :class="[darkTheme ? 'border-dark' : 'border-light']">
<header :class="[darkTheme ? 'border-dark' : 'border-light']" class="rounded overflow-hidden mb-3">
<b-carousel
v-if="hasArtworks"
id="carousel-fade"

View file

@ -1,10 +1,5 @@
<template lang="html">
<div
v-if="user && boardsWithGame.length"
class="p-3 rounded"
style="max-height: 50vh; overflow-y: auto;"
:class="darkTheme ? 'bg-dark' : 'bg-light'"
>
<div v-if="user && boardsWithGame.length">
<h4 class="mb-2">Found in {{ boardsWithGame.length }} boards</h4>
<MiniBoard
@ -12,6 +7,7 @@
:key="board.id"
:board="board"
:gameId="game.id"
class="mb-3"
@click.native="handleBoardClick(board.id)"
/>
</div>

View file

@ -34,7 +34,7 @@
:header-text-variant="darkTheme ? 'light' : 'dark'"
:body-bg-variant="darkTheme ? 'dark' : 'transparent'"
:body-text-variant="darkTheme ? 'light' : 'dark'"
@hidden="activeIndex = null"
@hidden="activeIndex = 0"
>
<template v-slot:modal-header="{ close }">
<modal-header
@ -68,14 +68,16 @@
allowfullscreen
/>
<b-img
v-else
rounded
fluid
:src="selectedMedia.imageUrl"
class="cursor-pointer w-auto"
style="max-height: 75vh;"
/>
<a v-else :href="selectedMedia.imageUrl">
<b-img
rounded
fluid
:src="selectedMedia.imageUrl"
class="cursor-pointer w-auto"
target="_blank"
style="max-height: 75vh;"
/>
</a>
</div>
</div>
</b-modal>
@ -88,7 +90,7 @@ import { mapGetters, mapState } from 'vuex';
export default {
data() {
return {
activeIndex: null,
activeIndex: 0,
saving: false,
};
},

View file

@ -1,5 +1,5 @@
<template lang="html">
<div v-if="user">
<div v-if="user" style="width: 200px">
{{ progress }}% Completed
<b-form-input

View file

@ -1,34 +1,25 @@
<!-- TODO: add pagination, limit to 6 per page -->
<template>
<!-- TODO: add pagination, limit to 6 per page -->
<div
v-if="allGames.length"
class="bg-light p-3 rounded"
:class="darkTheme ? 'bg-dark' : 'bg-light'"
>
<div v-if="allGames.length">
<h3>You may also like</h3>
<div
class="overflow-auto"
style="max-height: 50vh;"
<masonry
v-if="allGames.length"
gutter="16px"
:cols="{ default: 3, 1200: 6, 768: 3 }"
>
<masonry
v-if="allGames.length"
gutter="16px"
:cols="{ default: 3, 1200: 6, 768: 3 }"
>
<game-card-search
v-for="game in allGames"
:game="game"
:key="game && game.id"
/>
</masonry>
</div>
<game-card-search
v-for="game in allGames"
:game="game"
:key="game && game.id"
/>
</masonry>
</div>
</template>
<script>
import GameCardSearch from '@/components/GameCards/GameCardSearch';
import { mapState, mapGetters } from 'vuex';
import { mapState } from 'vuex';
import { getImageUrl } from '@/utils';
export default {
@ -40,7 +31,6 @@ export default {
computed: {
...mapState(['game']),
...mapGetters(['darkTheme']),
allGames() {
return [

View file

@ -3,7 +3,7 @@
v-if="game"
:img-src="$options.getImageUrl(game, $options.IMAGE_SIZE_COVER_SMALL)"
:img-alt="game.name"
class="mb-3 cursor-pointer"
class="mb-3 cursor-pointer border-0"
overlay
@click="handleClick"
>

View file

@ -6,16 +6,17 @@
<!-- :bg-variant="darkTheme ? 'dark' : 'light'" -->
<b-card
no-body
bg-variant="transparent"
content-class="bg-danger"
class="semi-transparent"
:class="darkTheme ? 'dark' : 'light'"
:text-variant="darkTheme ? 'light' : 'dark'"
>
<b-dropdown
v-if="isBoardOwner"
id="dropdown-1"
:variant="darkTheme ? 'dark' : 'light'"
class="mt-1 mx-2"
class="mt-1 mx-2 semi-transparent"
size="sm"
style="z-index: 1"
no-caret
block
>
@ -367,6 +368,18 @@ export default {
}
}
.semi-transparent {
backdrop-filter: saturate(180%) blur(20px);
&.dark {
background: rgba(53,54,58,.72);
}
&.light {
background: rgba(222,228,231,.72);
}
}
.list-settings {
padding: 1rem;
}

View file

@ -94,14 +94,14 @@ nav {
}
&.nav-left {
border: 0;
// border: 0;
left: 0;
// border-right: 1px solid var(--light);
}
&.nav-right {
border: 0;
border-left: 1px solid var(--light);
// border-left: 1px solid var(--light);
}
&.nav-left, &.nav-right {
@ -111,9 +111,9 @@ nav {
flex-direction: column;
}
&.bg-dark {
border-color: var(--black);
}
// &.bg-dark {
// border-color: var(--black);
// }
}
// .header-toggle {

View file

@ -17,7 +17,12 @@
<b-spinner small v-if="saving" />
<template v-else>
<i class="fa-solid fa-cloud-arrow-up fa-fw"></i>
<img
src="/img/dock-icons/upload-wallpaper.png"
alt="Wallpapers"
width="24"
/>
<span class="ml-2">Upload</span>
</template>
</b-dropdown-item>

View file

@ -127,7 +127,7 @@ export default {
this.$store.commit('SET_SESSION_EXPIRED', false);
this.$store.commit('SET_USER', user);
this.$router.push({ name: 'home' });
this.$router.replace({ name: 'boards' });
})
.catch((error) => {
this.handleError(error.code)
@ -232,7 +232,7 @@ export default {
// if (additionalUserInfo?.isNewUser) this.$store.dispatch('SEND_WELCOME_EMAIL', additionalUserInfo);
this.$store.commit('SET_SESSION_EXPIRED', false);
this.$store.commit('SET_USER', user);
this.$router.push({ name: 'home' });
this.$router.replace({ name: 'boards' });
this.$bus.$emit('BOOT');
},
},

View file

@ -0,0 +1,174 @@
<!-- TODO: add edit note page -->
<template lang="html">
<div>
<b-form-input
v-model="note.title"
class="mb-3"
placeholder="Title"
/>
<b-button-toolbar
v-if="editor"
key-nav
class="mb-3"
aria-label="Toolbar with button groups"
>
<b-button-group>
<b-button
@click="editor.chain().focus().setParagraph().run()"
v-b-tooltip.hover
title="Regular text"
size="sm"
:variant="editor.isActive('paragraph') ? 'dark' : 'light'"
>
<i class="fa-solid fa-font fa-fw" />
</b-button>
<b-button
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
v-b-tooltip.hover
title="Heading 1"
size="sm"
:variant="editor.isActive('heading', { level: 1 }) ? 'dark' : 'light'"
>
<span class="fa-layers fa-fw">
<i class="fa-solid fa-heading fa-fw" />
<i class="fa-solid fa-1" />
</span>
</b-button>
<b-button
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
v-b-tooltip.hover
title="Heading 2"
size="sm"
:variant="editor.isActive('heading', { level: 2 }) ? 'dark' : 'light'"
>
<span class="fa-layers fa-fw">
<i class="fa-solid fa-heading fa-fw" />
<i class="fa-solid fa-2" />
</span>
</b-button>
<b-button
@click="editor.chain().focus().toggleHeading({ level: 3 }).run()"
v-b-tooltip.hover
title="Heading 3"
size="sm"
:variant="editor.isActive('heading', { level: 3 }) ? 'dark' : 'light'"
>
<span class="fa-layers fa-fw">
<i class="fa-solid fa-heading fa-fw" />
<i class="fa-solid fa-3" />
</span>
</b-button>
</b-button-group>
<b-button-group class="mx-3">
<b-button
@click="editor.chain().focus().toggleBold().run()"
v-b-tooltip.hover
title="Bold"
size="sm"
:variant="editor.isActive('bold') ? 'dark' : 'light'"
>
<i class="fa-solid fa-bold fa-fw" />
</b-button>
<b-button
@click="editor.chain().focus().toggleItalic().run()"
v-b-tooltip.hover
title="Italic"
size="sm"
:variant="editor.isActive('italic') ? 'dark' : 'light'"
>
<i class="fa-solid fa-italic fa-fw" />
</b-button>
<b-button
@click="editor.chain().focus().toggleStrike().run()"
v-b-tooltip.hover
title="Strikethrough"
size="sm"
:variant="editor.isActive('strike') ? 'dark' : 'light'"
>
<i class="fa-solid fa-strikethrough fa-fw" />
</b-button>
</b-button-group>
</b-button-toolbar>
<editor-content :editor="editor" />
<b-link
class="small"
v-b-modal.markdown-cheatsheet
>
<i class="fab fa-markdown fa-fw" />
Markdown supported
</b-link>
<footer class="mt-3">
<b-button variant="primary" @click="saveNote">
Save note
</b-button>
</footer>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { Editor, EditorContent } from '@tiptap/vue-2';
import StarterKit from '@tiptap/starter-kit';
export default {
components: {
EditorContent,
},
data() {
return {
note: {
title: '',
body: '',
pinned: false,
backgroundColor: null,
games: [],
public: false,
},
saving: false,
editor: null,
};
},
computed: {
...mapState(['user']),
},
mounted() {
this.editor = new Editor({
content: this.note.body,
extensions: [StarterKit],
editorProps: {
attributes: {
class: 'border rounded p-3',
},
},
onUpdate: () => {
this.note.body = this.editor.getHTML();
},
});
},
methods: {
saveNote() {
const payload = {
...this.note,
owner: this.user?.uid,
}
this.$store.dispatch('CREATE_NOTE_V2', payload)
// const game = this.cachedGames[gameId];
// this.$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug } });
},
},
};
</script>

View file

@ -1,3 +1,4 @@
<!-- TODO: refresh cached game on game id change -->
<!-- TODO: fix background, add options? -->
<template lang="html">
<div v-if="!loading && !game" class="pt-5">
@ -49,7 +50,7 @@
<b-col
cols="12"
sm="6"
md="6"
md="7"
lg="8"
xl="5"
>
@ -59,18 +60,6 @@
v-b-visible="(value) => titleVisible = !value"
>
<div :class="['d-flex align-items-center']">
<!-- TODO: put like button in component, pass gameId -->
<!-- TODO: if liked, show dropdown when clicked, options: remove from your games -->
<b-button
variant="transparent"
squared
class="mr-2 p-0"
:disabled="!user"
@click="$bus.$emit('SELECT_GAME', gameId)"
>
<i :class="[isLiked ? 'fa-solid': 'fa-regular' , 'fa-heart text-danger']" />
</b-button>
<h2 id="popover-target-1" :class="{ 'text-danger': isLiked, 'cursor-pointer': alternativeNames.length }">
{{ gameName }}
</h2>
@ -179,95 +168,70 @@
</b-link>
<div class="mt-3">
<div v-if="gameGenres" class="float-left mr-3">
<h5>Genres</h5>
<div v-if="gameGenres" class="float-left mr-3 mb-3">
<h4>Genres</h4>
<b-button-group class="mb-3">
<b-button
<router-link
v-for="genre in gameGenres"
:to="{ name: 'search', query: { filterBy: 'genres', value: genre.id }}"
:key="genre.id"
size="sm"
variant="light"
>
<i :class="genre.icon || 'fa-solid fa-asterisk'" aria-hidden="true" />
<br />
<small>{{ genre.name }}</small>
</b-button>
</b-button-group>
<br />
</router-link>
</div>
<div v-if="gameThemes" class="float-left mr-3">
<h5>Themes</h5>
<div v-if="gameThemes" class="float-left mr-3 mb-3">
<h4>Themes</h4>
<b-button-group class="mb-3">
<b-button
v-for="theme in gameThemes"
:to="{ name: 'search', query: { filterBy: 'themes', value: theme.id }}"
:key="theme.id"
size="sm"
variant="light"
>
<i :class="theme.icon || 'fa-solid fa-asterisk'" aria-hidden="true" />
<br />
<small>{{ theme.name }}</small>
</b-button>
</b-button-group>
<router-link
v-for="theme in gameThemes"
:to="{ name: 'search', query: { filterBy: 'themes', value: theme.id }}"
:key="theme.id"
>
<small>{{ theme.name }}</small>
<br />
</router-link>
</div>
<div v-if="gameModes" class="float-left mr-3">
<h5>{{ $t('board.gameModal.gameModes') }} </h5>
<div v-if="gameModes" class="float-left mr-3 mb-3">
<h4>{{ $t('board.gameModal.gameModes') }} </h4>
<b-button-group class="mb-3">
<b-button
v-for="gameMode in gameModes"
:key="gameMode.id"
:to="{ name: 'search', query: { filterBy: 'game_modes', value: gameMode.id }}"
size="sm"
variant="light"
>
<i :class="gameMode.icon || 'fa-solid fa-gamepad'" aria-hidden="true" />
<br />
<small>{{ gameMode.name }}</small>
</b-button>
</b-button-group>
<router-link
v-for="gameMode in gameModes"
:key="gameMode.id"
:to="{ name: 'search', query: { filterBy: 'game_modes', value: gameMode.id }}"
>
<small>{{ gameMode.name }}</small>
<br />
</router-link>
</div>
<div v-if="gameEngines" class="float-left mr-3">
<h5>Game engines</h5>
<div v-if="gameEngines" class="float-left mr-3 mb-3">
<h4>Game engines</h4>
<b-button-group class="mb-3">
<b-button
v-for="gameEngine in gameEngines"
:key="gameEngine.id"
size="sm"
variant="light"
<span
v-for="gameEngine in gameEngines"
:key="gameEngine.id"
>
<!-- :to="{ name: 'search', query: { filterBy: 'game_modes', value: gameEngine.id }}" -->
<i :class="gameEngine.icon || 'fa-solid fa-asterisk'" aria-hidden="true" />
<br />
<small>{{ gameEngine.name }}</small>
</b-button>
</b-button-group>
<!-- :to="{ name: 'search', query: { filterBy: 'game_modes', value: gameEngine.id }}" -->
<small>{{ gameEngine.name }}</small>
<br />
</span>
</div>
<div v-if="playerPerspectives" class="float-left mr-3">
<h5>Perspective</h5>
<div v-if="playerPerspectives" class="float-left mr-3 mb-3">
<h4>Perspective</h4>
<b-button-group class="mb-3">
<b-button
v-for="perspective in playerPerspectives"
:key="perspective.id"
:to="{ name: 'search', query: { filterBy: 'player_perspectives', value: id }}"
size="sm"
variant="light"
>
<!-- :to="{ name: 'search', query: { filterBy: 'game_modes', value: perspective.id }}" -->
<i :class="perspective.icon || 'fa-solid fa-asterisk'" aria-hidden="true" />
<br />
<small>{{ perspective.name }}</small>
</b-button>
</b-button-group>
<router-link
v-for="perspective in playerPerspectives"
:key="perspective.id"
:to="{ name: 'search', query: { filterBy: 'player_perspectives', value: id }}"
>
<!-- :to="{ name: 'search', query: { filterBy: 'game_modes', value: perspective.id }}" -->
<small>{{ perspective.name }}</small>
<br />
</router-link>
</div>
<!-- <div>
@ -299,8 +263,8 @@
</b-col> -->
</div>
<div v-if="gamePlatforms" class="d-inline-block w-100">
<h5>Available for</h5>
<div v-if="gamePlatforms" class="d-inline-block w-100 mb-3">
<h4>Available for</h4>
<b-link
v-for="platform in gamePlatforms"
@ -310,7 +274,8 @@
class="mr-2 mb-2"
:to="{ name: 'search', query: { filterBy: 'platforms', value: platform.id }}"
>
{{ platform.name }}
<small>{{ platform.name }}</small>
<br />
</b-link>
</div>
@ -343,11 +308,11 @@
<b-col
cols="12"
xl="3"
xl="4"
>
<game-header />
<GameInBoards class="mb-3" />
<SimilarGames />
<SimilarGames class="mt-sm-5" />
</b-col>
</b-row>
@ -625,10 +590,6 @@ export default {
});
},
hasArtworks() {
return this.game?.artworks?.length > 0;
},
metacriticScore() {
return this.game?.steam?.metacritic;
},

View file

@ -16,7 +16,7 @@
<b-spinner v-if="loading" class="spinner-centered" />
<template v-else>
<game-selector
<!-- <game-selector
v-if="!isEmpty"
title="Select game to add a note"
:variant="darkTheme ? 'success' : 'primary'"
@ -25,7 +25,7 @@
>
<i class="d-sm-none fa-solid fa-plus" />
<span class="d-none d-sm-inline">Create note</span>
</game-selector>
</game-selector> -->
<empty-state
v-if="isEmpty"
@ -75,15 +75,19 @@
gutter="8px"
>
<b-card
v-for="({ note, game }, index) in filteredNotes"
v-for="note in notes"
body-class="p-2"
:bg-variant="darkTheme ? 'dark' : 'light'"
:text-variant="darkTheme ? 'light' : 'dark'"
:key="index"
:key="note"
class="cursor-pointer mb-2"
@click="$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug }})"
>
<b-card-text v-if="game">
<h2>{{ note.title }}</h2>
<p v-html="note.body" />
<!-- TODO: use correct route -->
<!-- @click="$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug }})" -->
<!-- <b-card-text v-if="game">
<b-img
:src="$options.getImageUrl(game, $options.IMAGE_SIZE_COVER_SMALL)"
height="80"
@ -95,7 +99,7 @@
</div>
<p class="note-text small" v-if="note" v-html="note" />
</b-card-text>
</b-card-text> -->
</b-card>
</masonry>
</template>
@ -134,29 +138,30 @@ export default {
return !Object.keys(this.notes).length;
},
filteredNotes() {
const notes = Object.entries(this.notes).map(([gameId, note]) => ({
note,
game: this.cachedGames?.[gameId],
}));
// filteredNotes() {
// const notes = Object.entries(this.notes).map(([gameId, note]) => ({
// note,
// game: this.cachedGames?.[gameId],
// }));
const searchText = this.searchText?.toLowerCase();
// const searchText = this.searchText?.toLowerCase();
if (searchText) {
return notes.filter(({ game, note }) => {
const noteIsMatch = note?.toLowerCase()?.includes(searchText);
const titleIsMatch = game?.name?.toLowerCase()?.includes(searchText);
// if (searchText) {
// return notes.filter(({ game, note }) => {
// const noteIsMatch = note?.toLowerCase()?.includes(searchText);
// const titleIsMatch = game?.name?.toLowerCase()?.includes(searchText);
return noteIsMatch || titleIsMatch;
});
}
// return noteIsMatch || titleIsMatch;
// });
// }
return notes;
},
// return notes;
// },
},
mounted() {
this.loadGames();
// this.loadGames();
this.loadNotes();
},
methods: {
@ -166,21 +171,25 @@ export default {
this.$router.push({ name: 'game.notes', params: { id: game.id, slug: game.slug } });
},
async loadGames() {
if (this.isEmpty) return;
loadNotes() {
const gamesList = Object.keys(this.notes);
this.loading = true;
try {
await this.$store.dispatch('LOAD_IGDB_GAMES', gamesList);
} catch (e) {
this.$bvToast.toast('Error loading games', { variant: 'error' });
}
this.loading = false;
},
// async loadGames() {
// if (this.isEmpty) return;
// const gamesList = Object.keys(this.notes);
// this.loading = true;
// try {
// await this.$store.dispatch('LOAD_IGDB_GAMES', gamesList);
// } catch (e) {
// this.$bvToast.toast('Error loading games', { variant: 'error' });
// }
// this.loading = false;
// },
},
};
</script>

View file

@ -4,28 +4,7 @@
<h3>Search</h3>
</portal>
<div class="d-flex">
<SearchBox :loading="loading" />
<div>
<b-button
v-if="showPreviousButton"
@click="prev"
>
<i class="fa-solid fa-caret-left" aria-hidden="true" />
Prev
</b-button>
<b-button
class="ml-3"
v-if="searchResults.length === pageSize"
@click="next"
>
Next
<i class="fa-solid fa-caret-right" aria-hidden="true" />
</b-button>
</div>
</div>
<SearchBox :loading="loading" />
<header class="mb-3 d-flex justify-content-between bg-danger">
<!-- <b-button v-b-modal.filters>
@ -48,16 +27,18 @@
</masonry>
<b-button
v-if="searchResults.length === pageSize"
v-if="searchResults.length <= pageSize"
block
class="mb-2"
@click="next"
@click="loadMore"
>
<b-spinner v-if="loading" />
<span v-else>
More results
</span>
<pre>{{ searchResults.length }}</pre>
<pre>{{ pageSize }}</pre>
</b-button>
<p
@ -173,7 +154,12 @@ export default {
},
methods: {
next() {
clearResults() {
this.searchResults = [];
console.log('results cleared');
},
loadMore() {
this.offset = this.offset + this.pageSize;
this.search();
},
@ -186,6 +172,10 @@ export default {
async search() {
this.loading = true;
if (this.searchResults.length > 0 && this.offset === 0) {
this.clearResults();
}
const search = this.query
? `search "${this.query}";`
: '';
@ -198,11 +188,16 @@ export default {
? `where ${this.filterBy} = (${this.filterValue});`
: '';
this.searchResults = await this.$store.dispatch('IGDB', {
const searchResults = await this.$store.dispatch('IGDB', {
path: 'games',
data: `${search} ${IGDB_QUERIES.SEARCH} limit ${this.pageSize}; offset ${this.offset}; ${filter};`,
});
this.searchResults = [
...this.searchResults,
...searchResults,
]
this.loading = false;
},
},

View file

@ -13,7 +13,7 @@ const routes = [
path: '/boards',
component: () => import(/* webpackChunkName: "games" */ '@/pages/BoardsPage'),
meta: {
title: 'My games',
title: 'My boards',
public: true,
},
},
@ -22,7 +22,7 @@ const routes = [
path: '/public-boards',
component: () => import(/* webpackChunkName: "games" */ '@/pages/PublicBoardsPage'),
meta: {
title: 'My games',
title: 'My boards',
public: true,
},
},
@ -158,6 +158,23 @@ const routes = [
public: true,
},
},
{
name: 'create.note',
path: '/notes/create',
component: () => import(/* webpackChunkName: "notes" */ '@/pages/CreateNotePage'),
meta: {
title: 'Create note',
},
},
// {
// name: 'note',
// path: '/notes/:id',
// component: () => import(/* webpackChunkName: "notes" */ '@/pages/NotePage'),
// meta: {
// title: 'Notes',
// public: true,
// },
// },
{
name: 'profiles',
path: '/profiles',

View file

@ -172,9 +172,15 @@ export default {
},
async LOAD_NOTES({ commit, state }) {
const docSnap = await getDoc(doc(db, "notes", state.user.uid));
const q = query(collection(db, "notes-v2"), where("owner", "==", state.user.uid));
const querySnapshot = await getDocs(q);
const notes = querySnapshot.docs.map((doc) => doc.data());
commit("SET_NOTES", docSnap.data());
console.log(notes);
commit("SET_NOTES", notes);
},
async LOAD_TAGS({ commit, state }) {
@ -221,6 +227,15 @@ export default {
await setDoc(doc(db, "notes", state.user.uid), state.notes, { merge: true });
},
async CREATE_NOTE_V2(context, note) {
const docRef = await addDoc(collection(db, "notes-v2"), note);
console.log(docRef);
// commit("ADD_BOARD", newBoard);
return note;
},
async SAVE_GAMES({ state }) {
await setDoc(doc(db, "games", state.user.uid), state.games);
},

View file

@ -144,10 +144,10 @@ export default {
// console.log('speedRunVideos', speedRunVideos);
return [
...igdbArtworks,
...igdbScreenshots,
...gogImages,
...steamScreenshots,
...igdbArtworks,
...wikipediaImages,
gameCover,
...speedRunVideos,