mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
feat: 🎨 Move collection functions to a util. Button to add on game page as well. Add icon component and feather icons..
This commit is contained in:
parent
9bef4328cb
commit
1f847c91e7
9 changed files with 109 additions and 82 deletions
|
|
@ -44,7 +44,9 @@
|
|||
"@leveluptuts/svelte-side-menu": "^1.0.2",
|
||||
"@leveluptuts/svelte-toy": "^2.0.2",
|
||||
"@lukeed/uuid": "^2.0.0",
|
||||
"@types/feather-icons": "^4.7.0",
|
||||
"cookie": "^0.5.0",
|
||||
"feather-icons": "^4.29.0",
|
||||
"zod": "^3.17.10"
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ specifiers:
|
|||
'@sveltejs/adapter-auto': 1.0.0-next.63
|
||||
'@sveltejs/kit': 1.0.0-next.392
|
||||
'@types/cookie': ^0.5.1
|
||||
'@types/feather-icons': ^4.7.0
|
||||
'@types/node': ^18.0.6
|
||||
'@typescript-eslint/eslint-plugin': ^5.27.0
|
||||
'@typescript-eslint/parser': ^5.27.0
|
||||
|
|
@ -20,6 +21,7 @@ specifiers:
|
|||
eslint: ^8.19.0
|
||||
eslint-config-prettier: ^8.1.0
|
||||
eslint-plugin-svelte3: ^4.0.0
|
||||
feather-icons: ^4.29.0
|
||||
prettier: ^2.7.1
|
||||
prettier-plugin-svelte: ^2.7.0
|
||||
sass: ^1.54.0
|
||||
|
|
@ -36,7 +38,9 @@ dependencies:
|
|||
'@leveluptuts/svelte-side-menu': 1.0.2
|
||||
'@leveluptuts/svelte-toy': 2.0.2
|
||||
'@lukeed/uuid': 2.0.0
|
||||
'@types/feather-icons': 4.7.0
|
||||
cookie: 0.5.0
|
||||
feather-icons: 4.29.0
|
||||
zod: 3.17.10
|
||||
|
||||
devDependencies:
|
||||
|
|
@ -303,6 +307,10 @@ packages:
|
|||
resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
|
||||
dev: true
|
||||
|
||||
/@types/feather-icons/4.7.0:
|
||||
resolution: {integrity: sha512-vflOrmlHMGIGVN4AEl6ErPCNKBLcP1ehEpLqnJkTgf69r5QmJzy7BF1WzbBc8Hqs9KffROPT/JqlSKH4o5vB/w==}
|
||||
dev: false
|
||||
|
||||
/@types/json-schema/7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
dev: true
|
||||
|
|
@ -619,6 +627,10 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/classnames/2.3.1:
|
||||
resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==}
|
||||
dev: false
|
||||
|
||||
/color-convert/2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
|
@ -648,6 +660,11 @@ packages:
|
|||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/core-js/3.24.0:
|
||||
resolution: {integrity: sha512-IeOyT8A6iK37Ep4kZDD423mpi6JfPRoPUdQwEWYiGolvn4o6j2diaRzNfDfpTdu3a5qMbrGUzKUpYpRY8jXCkQ==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/cross-spawn/7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
|
@ -1101,6 +1118,13 @@ packages:
|
|||
reusify: 1.0.4
|
||||
dev: true
|
||||
|
||||
/feather-icons/4.29.0:
|
||||
resolution: {integrity: sha512-Y7VqN9FYb8KdaSF0qD1081HCkm0v4Eq/fpfQYQnubpqi0hXx14k+gF9iqtRys1SIcTEi97xDi/fmsPFZ8xo0GQ==}
|
||||
dependencies:
|
||||
classnames: 2.3.1
|
||||
core-js: 3.24.0
|
||||
dev: false
|
||||
|
||||
/file-entry-cache/6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
|
|
|
|||
38
src/lib/components/Icon.svelte
Normal file
38
src/lib/components/Icon.svelte
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<script lang="ts">
|
||||
import feather from 'feather-icons';
|
||||
export const directions: string[] = ["n", "ne", "e", "se", "s", "sw", "w", "nw"];
|
||||
|
||||
export let name: string;
|
||||
export let direction: string = "n";
|
||||
export let strokeWidth: string | number;
|
||||
export let stroke: string | number;
|
||||
export let width: string = "1em";
|
||||
export let height: string = "1em";
|
||||
|
||||
$: icon = feather.icons[name];
|
||||
$: rotation = directions.indexOf(direction) * 45;
|
||||
$: if (icon) {
|
||||
if (stroke) icon.attrs["stroke"] = stroke;
|
||||
if (strokeWidth) icon.attrs["stroke-width"] = strokeWidth;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if icon}
|
||||
<svg
|
||||
{...icon.attrs}
|
||||
style="width: {width}; height: {height}; transform: rotate({rotation}deg);"
|
||||
>
|
||||
<g>
|
||||
{@html icon.contents}
|
||||
</g>
|
||||
</svg>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,21 +2,12 @@
|
|||
import { fade } from 'svelte/transition';
|
||||
import { ToastType, type GameType } from '$lib/types';
|
||||
import { collectionStore } from '$lib/stores/collectionStore';
|
||||
import { toast } from '../toast/toast';
|
||||
import { toast } from '$lib/components/toast/toast';
|
||||
import { addToCollection, removeFromCollection } from '$lib/util/manipulateCollection';
|
||||
|
||||
export let game: GameType;
|
||||
export let detailed: boolean = false;
|
||||
$: existsInCollection = $collectionStore.find((item: GameType) => item.id === game.id);
|
||||
|
||||
function addToCollection() {
|
||||
collectionStore.add(game)
|
||||
toast.send(`"${game.name}" added to collection!`, { duration: 3000, type: ToastType.INFO });
|
||||
}
|
||||
|
||||
function removeFromCollection() {
|
||||
collectionStore.remove(game.id)
|
||||
toast.send(`Removed "${game.name}" from collection!`, { duration: 3000, type: ToastType.INFO });
|
||||
}
|
||||
</script>
|
||||
|
||||
<article class="game-container" transition:fade>
|
||||
|
|
@ -38,9 +29,9 @@
|
|||
{/if}
|
||||
</div>
|
||||
{#if existsInCollection}
|
||||
<button type="button" on:click={removeFromCollection}>Remove from collection -</button>
|
||||
<button class="btn" type="button" on:click={() => removeFromCollection(game)}>Remove from collection -</button>
|
||||
{:else}
|
||||
<button type="button" on:click={addToCollection}>Add to collection +</button>
|
||||
<button class="btn" type="button" on:click={() => addToCollection(game)}>Add to collection +</button>
|
||||
{/if}
|
||||
|
||||
</article>
|
||||
|
|
|
|||
13
src/lib/util/manipulateCollection.ts
Normal file
13
src/lib/util/manipulateCollection.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { collectionStore } from '$lib/stores/collectionStore';
|
||||
import { toast } from '$lib/components/toast/toast';
|
||||
import { ToastType, type GameType } from '$lib/types';
|
||||
|
||||
export function addToCollection(game: GameType) {
|
||||
collectionStore.add(game)
|
||||
toast.send(`"${game.name}" added to collection!`, { duration: 3000, type: ToastType.INFO });
|
||||
}
|
||||
|
||||
export function removeFromCollection(game: GameType) {
|
||||
collectionStore.remove(game.id)
|
||||
toast.send(`Removed "${game.name}" from collection!`, { duration: 3000, type: ToastType.INFO });
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import type { SearchQuery } from '$lib/types';
|
||||
import type { GameType, SearchQuery } from '$lib/types';
|
||||
import { mapAPIGameToBoredGame } from '$lib/util/gameMapper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
const form = await request.formData();
|
||||
|
|
@ -45,8 +46,11 @@ export const POST: RequestHandler = async ({ request }) => {
|
|||
|
||||
if (response.status === 200) {
|
||||
const gameResponse = await response.json();
|
||||
const games = gameResponse?.games;
|
||||
console.log('games', games);
|
||||
const gameList = gameResponse?.games;
|
||||
const games: GameType[] = [];
|
||||
gameList.forEach(game => {
|
||||
games.push(mapAPIGameToBoredGame(game))
|
||||
});
|
||||
return {
|
||||
body: {
|
||||
games: gameResponse?.games
|
||||
|
|
|
|||
|
|
@ -99,8 +99,6 @@ export const POST: RequestHandler = async ({ request }) => {
|
|||
if (response.status === 200) {
|
||||
const gameResponse = await response.json();
|
||||
const gameList = gameResponse?.games;
|
||||
console.log('gameList', gameList);
|
||||
console.log('type', typeof gameList);
|
||||
const games: GameType[] = [];
|
||||
gameList.forEach(game => {
|
||||
games.push(mapAPIGameToBoredGame(game))
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { collectionStore } from '$lib/stores/collectionStore';
|
||||
import type { GameType } from '$lib/types';
|
||||
import Transition from '$lib/components/transition/index.svelte';
|
||||
import { Checkbox, NumberInput } from 'carbon-components-svelte';
|
||||
import type { boolean } from 'zod';
|
||||
// import { enhance } from "$lib/form";
|
||||
import { addToCollection, removeFromCollection } from '$lib/util/manipulateCollection';
|
||||
|
||||
$: existsInCollection = $collectionStore.find((item: GameType) => item.id === game.id);
|
||||
export let game: GameType;
|
||||
let seeMore: boolean = false;
|
||||
console.log(game?.description?.indexOf('</p>'));
|
||||
|
|
@ -31,14 +31,17 @@
|
|||
</a>
|
||||
</div>
|
||||
<div class="details">
|
||||
<div>
|
||||
<p>Year Published: {game?.year_published}</p>
|
||||
<p>Players: {game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
|
||||
<p>Playtime: {game.playtime} minutes</p>
|
||||
<p>Minimum Age: {game.min_age}</p>
|
||||
<p>Price: ${game?.price}</p>
|
||||
<a href={game.url} rel="noreferrer">Board Game Atlas Link</a>
|
||||
</div>
|
||||
<p>Year Published: {game?.year_published}</p>
|
||||
<p>Players: {game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
|
||||
<p>Playtime: {game.playtime} minutes</p>
|
||||
<p>Minimum Age: {game.min_age}</p>
|
||||
<p>Price: ${game?.price}</p>
|
||||
<a style="display: flex; gap: 1rem;" href={game.url} target="_blank" rel="noreferrer">Board Game Atlas Link <Icon name="external-link" /></a>
|
||||
{#if existsInCollection}
|
||||
<button class="btn" type="button" on:click={() => removeFromCollection(game)}>Remove from collection -</button>
|
||||
{:else}
|
||||
<button class="btn" type="button" on:click={() => addToCollection(game)}>Add to collection +</button>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
{#if firstParagraphEnd > 0}
|
||||
|
|
@ -52,7 +55,7 @@
|
|||
{@html game?.description?.substring(firstParagraphEnd + 1)}
|
||||
</span>
|
||||
{/if}
|
||||
<button on:click={() => (seeMore = !seeMore)}>See {!seeMore ? 'More +' : 'Less -'}</button>
|
||||
<button class="btn" type="button" on:click={() => (seeMore = !seeMore)}>See {!seeMore ? 'More +' : 'Less -'}</button>
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
|
|
@ -68,8 +71,8 @@
|
|||
button {
|
||||
border-radius: 4px;
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
max-width: 200px;
|
||||
padding: 1rem;
|
||||
max-width: 30rem;
|
||||
background-color: var(--color-btn-primary-active);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +85,9 @@
|
|||
|
||||
.details {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
gap: 0.5rem;
|
||||
align-content: center;
|
||||
justify-content: start;
|
||||
margin: 1rem;
|
||||
a,
|
||||
p {
|
||||
|
|
|
|||
|
|
@ -32,51 +32,3 @@ export const GET: RequestHandler = async ({ params }) => {
|
|||
status: response.status
|
||||
};
|
||||
}
|
||||
|
||||
// export const post: RequestHandler = async ({ request }) => {
|
||||
// const form = await request.formData();
|
||||
// const minAge = form.get('minAge') || 0;
|
||||
// console.log('minAge', minAge);
|
||||
// const maxAge = form.get('maxAge') || 0;
|
||||
// console.log('maxAge', maxAge);
|
||||
// const minPlayers = form.get('minPlayers') || 1;
|
||||
// console.log('minPlayers', minPlayers);
|
||||
// const maxPlayers = form.get('maxPlayers') || 1;
|
||||
// console.log('maxPlayers', maxPlayers);
|
||||
|
||||
// const queryParams = {
|
||||
// order_by: 'rank',
|
||||
// ascending: 'false',
|
||||
// limit: '1',
|
||||
// gt_min_players: String(+minPlayers === 1 ? 0 : +minPlayers - 1),
|
||||
// lt_max_players: String(+maxPlayers + 1),
|
||||
// gt_min_age: String(+minAge === 1 ? 0 : +minAge - 1),
|
||||
// lt_max_age: String(+maxAge + 1),
|
||||
// }
|
||||
// const response = await boardGameApi('get', `search`, queryParams);
|
||||
// console.log('response', response);
|
||||
// if (response.status === 404) {
|
||||
// // user hasn't created a todo list.
|
||||
// // start with an empty array
|
||||
// return {
|
||||
// body: {
|
||||
// games: []
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// if (response.status === 200) {
|
||||
// const gameResponse = await response.json();
|
||||
// const games = gameResponse?.games;
|
||||
// console.log('games', games);
|
||||
// return {
|
||||
// body: {
|
||||
// games,
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// return {
|
||||
// status: response.status
|
||||
// };
|
||||
// }
|
||||
|
|
|
|||
Loading…
Reference in a new issue