feat: nicer stall cards

This commit is contained in:
Vlad Stan 2023-07-14 15:33:54 +03:00
parent ad0ac073ab
commit 1f0ea23359
5 changed files with 70 additions and 34 deletions

View file

@ -40,16 +40,8 @@ async function customerMarket(path) {
methods: {
refreshProducts: function () {
this.showProducts = false
const searchText = this.searchText?.toLowerCase() || ''
this.partialProducts = []
if (searchText.length < 3) {
this.lastProductIndex = Math.min(this.filteredProducts.length, this.productsPerPage)
this.partialProducts.push(...this.filteredProducts.slice(0, this.lastProductIndex))
setTimeout(() => this.showProducts = true, 0)
return
}
this.startIndex = 0
this.lastProductIndex = Math.min(this.filteredProducts.length, this.productsPerPage)
this.partialProducts.push(...this.filteredProducts.slice(0, this.lastProductIndex))

View file

@ -1,9 +1,14 @@
<div class="row q-col-gutter-md">
<div v-if="showStalls" class="row q-col-gutter-md">
<div v-for="stall of stalls" :key="stall.id" class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<q-card class="card--product">
<!-- <q-img
:src="(product.images && product.images.length > 0 && product.images[0]) ? product.images[0] : '/nostrmarket/static/images/placeholder.png'"
alt="Product Image" loading="lazy" spinner-color="white" fit="contain" height="300px"></q-img> -->
<q-card-section class="q-pb-xs q-pt-md">
<div class="q-pa-md q-gutter-sm" style="height: 80px">
<q-avatar v-for="(image, i) of stall.images" :key="i" size="40px" class="overlapping"
:style="`left: ${i * 25}px; border: 2px solid white; position: absolute`">
<img :src="image">
</q-avatar>
</div>
</q-card-section>
<q-card-section class="q-pb-xs q-pt-md">
<div class="row no-wrap items-center">
@ -11,21 +16,21 @@
</div>
</q-card-section>
<q-separator />
<q-card-section class="q-py-sm">
<q-card-section class="q-pl-sm">
<div>
<span v-if="stall.currency == 'sat'">
<!-- <span class="text-h6">{{ product.price }} sats</span><q-tooltip> BTC {{ (product.price /
1e8).toFixed(8) }}</q-tooltip> -->
currency sat
</span>
<span v-else>
<span class="text-h6">currency fiat</span>
</span>
<span class="q-ml-md text-caption text-green-8 text-weight-bolder q-mt-md">product count</span>
<span class="text-caption text-green-8 text-weight-bolder q-mt-md"><span v-text="stall.productCount"></span>
products</span>
<span v-text="stall.currency" class="float-right"></span>
</div>
</q-card-section>
<!-- <q-card-section class="q-pl-sm">
</q-card-section> -->
<q-card-section class="q-pl-sm">
<div v-if="stall.categories" class="text-subtitle1">
<q-virtual-scroll :items="product.categories || []" virtual-scroll-horizontal>
<q-virtual-scroll :items="stall.categories || []" virtual-scroll-horizontal>
<template v-slot="{ item, index }">
<q-chip :key="index" dense><span v-text="item"></span></q-chip>
</template>

View file

@ -7,7 +7,15 @@ async function customerStallList(path) {
props: ['stalls'],
data: function () {
return {}
return {
showStalls: true
}
},
watch: {
stalls() {
this.showProducts = false
setTimeout(() => { this.showProducts = true }, 0)
}
},
computed: {},
methods: {

View file

@ -119,15 +119,36 @@ const market = async () => {
}
if (!this.searchText || this.searchText.length < 2) return products
const searchText = this.searchText.toLowerCase()
return products.filter(p => {
return (
p.name.toLowerCase().includes(searchText) ||
(p.description &&
p.description.toLowerCase().includes(searchText)) ||
(p.categories &&
p.categories.toString().toLowerCase().includes(searchText))
)
})
return products.filter(p => (
p.name.toLowerCase().includes(searchText) ||
(p.description &&
p.description.toLowerCase().includes(searchText)) ||
(p.categories &&
p.categories.toString().toLowerCase().includes(searchText))
)
)
},
filterStalls() {
const stalls = this.stalls
.map(s => (
{
...s,
categories: this.allStallCatgories(s.id),
images: this.allStallImages(s.id).slice(0, 8),
productCount: this.products.filter(p => p.stall_id === s.id).length
}))
.filter(p => this.hasCategory(p.categories))
if (!this.searchText || this.searchText.length < 2) return stalls
const searchText = this.searchText.toLowerCase()
return this.stalls.filter(s => (
s.name.toLowerCase().includes(searchText) ||
(s.description &&
s.description.toLowerCase().includes(searchText)) ||
(s.categories &&
s.categories.toString().toLowerCase().includes(searchText))
))
},
stallName() {
return this.stalls.find(s => s.id == this.activeStall)?.name || 'Stall'
@ -902,6 +923,14 @@ const market = async () => {
}
return false
},
allStallCatgories(stallId) {
const categories = this.products.filter(p => p.stall_id === stallId).map(p => p.categories).flat().filter(c => !!c)
return Array.from(new Set(categories))
},
allStallImages(stallId) {
const images = this.products.filter(p => p.stall_id === stallId).map(p => p.images && p.images[0]).filter(i => !!i)
return Array.from(new Set(images))
}
}
})

View file

@ -289,7 +289,8 @@
@login-dialog="openAccountDialog" @change-page="navigateTo" @add-to-cart="addProductToCart"></customer-stall>
<div v-else>
<customer-stall-list v-if="groupByStall" :stalls="stalls"></customer-stall-list>
<customer-stall-list v-if="groupByStall" :stalls="filterStalls"
@change-page="navigateTo"></customer-stall-list>
<customer-market v-else :search-nostr="searchNostr" :relays="relays" :filtered-products="filterProducts"
:search-text="searchText" :filter-categories="filterCategories" :styles="config?.opts ?? {}"
@ -445,4 +446,5 @@
text-overflow: ellipsis;
}
</style>
{% endblock %}