Compare commits

..

2 Commits

Author SHA1 Message Date
dfa93c5c74 Merge branch 'by-seller' 2024-03-03 13:07:40 -05:00
e783bf5a62 add per-seller listing 2024-03-03 13:06:46 -05:00
4 changed files with 278 additions and 0 deletions

View File

@ -28,6 +28,10 @@
<i>list</i> <i>list</i>
<span class="max">listing</span> <span class="max">listing</span>
</a> </a>
<a href="/sellers" on:click={hide_menu}>
<i>list</i>
<span class="max">listing by sellers</span>
</a>
<a href="/cart/" on:click={hide_menu}> <a href="/cart/" on:click={hide_menu}>
<i>shopping_cart</i> <i>shopping_cart</i>
<span>cart</span> <span>cart</span>

View File

@ -0,0 +1,91 @@
<article>
{#if $games.length == 0}
<div class="medium-height middle-align center-align">
<div class="center-align">
<progress class="circle"></progress>
<h5>gathering games...</h5>
</div>
</div>
{:else}
{#each Object.keys($sellers).sort() as username (username)}
<div class="row">
<h4 class="small">
<a name={`seller-${username}`} href={`#seller-${username}`}>
<i>link</i></a>
<BggUser {username} />
</h4>
<span class="max neighbourhood">
{#if $sellers[username].neighbourhood}
({$sellers[username].neighbourhood})
{/if}
</span>
<span class="nbr_games">
{nbr_games_for(username)}
</span>
</div>
<GameList
sellers={$sellers}
games={$games.filter((game) => game.username === username)} />
{/each}
{/if}
</article>
<script>
import { getContext } from 'svelte';
import GameList from './GameList.svelte';
import BggUser from '$lib/components/BggUser.svelte';
const games = getContext('games');
const sellers = getContext('sellers');
const nbr_games_for = (username) =>
$games.filter((game) => game.username === username).length;
</script>
<style>
p {
font-size: var(--font-size-10);
max-width: 60em;
text-align: justify;
margin-left: 3em;
margin-right: 3em;
}
a {
color: var(--primary);
text-decoration: underline;
}
.game-cell {
display: flex;
}
.game-cell > * {
display: block;
}
.game-desc {
flex: 1;
}
td {
font-size: var(--font-size-10);
}
@media screen and (max-width: 730px) {
h1 {
font-size: var(--font-size-12);
}
p {
font-size: inherit;
margin-left: 1em;
margin-right: 1em;
}
}
.nbr_games:after {
content: ' games';
}
.nbr_games:before {
content: 'selling ';
}
a {
padding-right: 1em;
}
</style>

View File

@ -0,0 +1,121 @@
<div transition:slide={{ delay: 250, duration: 300 }} class="game">
<div class="grid top-align">
<div class="s12 m2">
<a
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
<img alt="" loading="lazy" src={thumbnail} height="80" /></a>
</div>
<div class="grid s12 m10">
<div class="s9 left-align">
<div class="max">
{#if is_in_cart}
<i class="star">star</i>
{/if}
<strong>
<a
name={id}
class="game-desc"
target="_blank"
href={`https://boardgamegeek.com/boardgame/${bgg_id}`}>
{name}</a>
</strong>
&nbsp; &nbsp; &nbsp;
<a href={`https://bgg.babyl.ca/#${id}`}><i>link</i></a>
</div>
</div>
<div class="s1 right-align">
{price ? '$' + price : ''}
</div>
<div class="notes s8">
{notes}
</div>
<div class="s4 updated-at">
{#if updated_at}
{pretty_date(updated_at)}
{/if}
</div>
<div class="s1"></div>
<div class="s11 actions">
<button on:click={toggle_cart}
><i>
{#if is_in_cart}
remove_shopping_cart{:else}
add_shopping_cart
{/if}
</i></button>
</div>
</div>
</div>
</div>
<script>
// TODO show cart icon with badge
// show cart page
// cart store
import { createEventDispatcher } from 'svelte';
import { slide, fade } from 'svelte/transition';
export let username = '';
export let name = '';
export let is_hidden = false;
export let bgg_id = '';
export let thumbnail = '';
export let seller = {};
export let price = null;
export let notes = '';
export let updated_at = null;
export let is_in_cart = false;
export let id = '';
function pretty_date(date) {
if (!date) return '';
return date.replace(/T.*/, '');
}
const dispatch = createEventDispatcher();
const toggle_game_visibility = () => dispatch('toggle_visibility');
const toggle_cart = () => dispatch('toggle_cart');
</script>
<style>
a {
color: var(--primary);
text-decoration: underline;
}
.grid {
margin-right: 2em;
font-size: var(--font-size-10);
}
.notes {
margin-top: 1em;
margin-left: 1em;
}
.updated-at {
font-size: smaller;
text-align: left;
}
.updated-at::before {
content: 'last update: ';
}
.neighbourhood {
font-size: smaller;
}
.hidden {
opacity: 60%;
}
.actions {
margin-top: 1em;
display: flex;
justify-content: end;
}
.actions button {
margin: 0.5em 2em 0em 1em;
}
.star {
color: darkorange;
font-size: var(--font-size-12);
}
</style>

View File

@ -0,0 +1,62 @@
<div class="games">
{#each games as game}
<Game
on:toggle_visibility={() => toggle_visibility(game.id)}
on:toggle_cart={() => toggle_cart(game.id)}
{...game}
seller={sellers[game.username]} />
<div class="medium-divider"></div>
{/each}
</div>
<script>
import { getContext, createEventDispatcher } from 'svelte';
import Game from './Game.svelte';
export let games = [];
export let sellers = {};
const toggle_cart = (id) => dispatch('toggle_cart', id);
</script>
<style>
.games {
margin-top: 3em;
}
a {
color: var(--primary);
text-decoration: underline;
}
.grid {
margin-right: 2em;
font-size: var(--font-size-10);
}
.notes {
margin-top: 1em;
margin-left: 1em;
}
.updated-at {
font-size: smaller;
text-align: left;
}
.updated-at::before {
content: 'last update: ';
}
.neighbourhood {
font-size: smaller;
}
.hidden {
opacity: 60%;
}
.switch span {
font-size: var(--font-size-10);
padding-left: 1em;
}
.options {
display: flex;
flex-direction: row-reverse;
}
.options > div {
margin-right: 1em;
}
</style>