moved facets to offcanvas, added button to search bar to open and stylized

This commit is contained in:
zach
2026-02-28 20:47:32 -05:00
parent 89a670523b
commit bfcbab2fd4
9 changed files with 63 additions and 34 deletions

View File

@@ -33,7 +33,7 @@
// @import 'bootstrap/scss/list-group'; // @import 'bootstrap/scss/list-group';
@import 'bootstrap/scss/modal'; @import 'bootstrap/scss/modal';
@import 'bootstrap/scss/navbar'; @import 'bootstrap/scss/navbar';
// @import 'bootstrap/scss/offcanvas'; @import 'bootstrap/scss/offcanvas';
// @import 'bootstrap/scss/pagination'; // @import 'bootstrap/scss/pagination';
// @import 'bootstrap/scss/placeholders'; // @import 'bootstrap/scss/placeholders';
// @import 'bootstrap/scss/popover'; // @import 'bootstrap/scss/popover';

View File

@@ -57,7 +57,7 @@
Navbar & Icons Navbar & Icons
-------------------------------------------------- */ -------------------------------------------------- */
.navbar { .navbar {
background-color: hsl(358, 71%, 48%) !important; background-color: var(--bs-danger) !important;
} }
.sticky-top { .sticky-top {
@@ -245,6 +245,7 @@ $tiers: (
.rarity-icon-large svg, .rarity-icon-large svg,
.set-icon svg { .set-icon svg {
width: 2.5rem; width: 2.5rem;
z-index: 999;
} }
.rarity-icon-large svg, .rarity-icon-large svg,
@@ -252,6 +253,18 @@ $tiers: (
margin-bottom: -0.25rem; margin-bottom: -0.25rem;
} }
.filter-icon svg {
width: 2rem;
fill: rgba(255,255,255,0.87);
stroke: rgba(255,255,255,0.87);
}
.search-button {
width: 2rem;
fill: rgba(255,255,255,0.87);
stroke: rgba(255,255,255,0.87);
}
.energy-icon svg { .energy-icon svg {
margin-top: -0.25rem; margin-top: -0.25rem;
margin-right: -0.25rem; margin-right: -0.25rem;
@@ -374,7 +387,7 @@ $tiers: (
} }
.facet-list { .facet-list {
max-height: 240px; max-height: 185px;
overflow-y: auto; overflow-y: auto;
} }

View File

@@ -1,20 +1,27 @@
--- ---
--- ---
<div class="row mb-4">
<div class="row mb-4"> <div class="col-md-3 display-sm-none">
<div class="col-md-3 display-sm-none"> <div class="h5 d-none">Inventory management placeholder</div>
<div class="h5 d-none">Inventory management placeholder</div> <div class="offcanvas offcanvas-start" data-bs-backdrop="static" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Filters</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body px-3 pt-0">
<div id="facetContainer"></div> <div id="facetContainer"></div>
</div> </div>
<div class="col-sm-12 col-md-9 mt-0">
<div id="cardGrid" class="row g-xxl-3 g-2 row-cols-2 row-cols-lg-3 row-cols-xxl-4 row-cols-xxxl-5">
</div>
</div> </div>
</div> </div>
<div class="modal fade card-modal" id="cardModal" tabindex="-1" aria-labelledby="cardModalLabel" aria-hidden="true"> <div class="col-sm-12 col-md-9 mt-0">
<div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl"> <div id="cardGrid" class="row g-xxl-3 g-2 row-cols-2 row-cols-lg-3 row-cols-xxl-4 row-cols-xxxl-5">
<div class="modal-content">
</div>
</div> </div>
</div> </div>
</div>
<div class="modal fade card-modal" id="cardModal" tabindex="-1" aria-labelledby="cardModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl">
<div class="modal-content">
</div>
</div>
</div>

View File

@@ -25,9 +25,14 @@ import { SignedIn } from "@clerk/astro/components";
<SignedIn> <SignedIn>
<form class="d-flex ms-2" role="search" id="searchform" hx-post="/partials/cards" hx-target="#cardGrid" hx-trigger="load, submit" hx-vals='{"start":"0"}' hx-on--after-request="afterUpdate()" hx-on--before-request="beforeSearch()"> <form class="d-flex ms-2" role="search" id="searchform" hx-post="/partials/cards" hx-target="#cardGrid" hx-trigger="load, submit" hx-vals='{"start":"0"}' hx-on--after-request="afterUpdate()" hx-on--before-request="beforeSearch()">
<a class="btn btn-secondary btn-lg me-2" data-bs-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample"><span class="d-block d-md-none filter-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path opacity=".4" d="M96 160L283.3 347.3C286.3 350.3 288 354.4 288 358.6L288 480L352 544L352 358.6C352 354.4 353.7 350.3 356.7 347.3L544 160L96 160z"/><path d="M66.4 147.8C71.4 135.8 83.1 128 96 128L544 128C556.9 128 568.6 135.8 573.6 147.8C578.6 159.8 575.8 173.5 566.7 182.7L384 365.3L384 544C384 556.9 376.2 568.6 364.2 573.6C352.2 578.6 338.5 575.8 329.3 566.7L265.3 502.7C259.3 496.7 255.9 488.6 255.9 480.1L256 365.3L73.4 182.6C64.2 173.5 61.5 159.7 66.4 147.8zM544 160L96 160L283.3 347.3C286.3 350.3 288 354.4 288 358.6L288 480L352 544L352 358.6C352 354.4 353.7 350.3 356.7 347.3L544 160z"/></svg></span><span class="d-none d-md-block">Filters</span></a>
<div class="input-group">
<input type="hidden" name="start" id="start" value="0" /> <input type="hidden" name="start" id="start" value="0" />
<input type="search" name="q" class="form-control form-control-lg me-2" placeholder="Search cards..." /> <input type="search" name="q" class="form-control form-control-lg form-outline" placeholder="Search cards..." />
<input type="submit" class="btn btn-outline-light" value="Search" onclick="const q = document.querySelector('[name=q]').value; dataLayer.push({ event: 'view_search_results', search_term: q });"/> <button type="submit" class="btn btn-danger btn-lg" value="" onclick="const q = document.querySelector('[name=q]').value; dataLayer.push({ event: 'view_search_results', search_term: q });">
<svg class="search-button d-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path d="M432 272C432 183.6 360.4 112 272 112C183.6 112 112 183.6 112 272C112 360.4 183.6 432 272 432C360.4 432 432 360.4 432 272zM401.1 435.1C365.7 463.2 320.8 480 272 480C157.1 480 64 386.9 64 272C64 157.1 157.1 64 272 64C386.9 64 480 157.1 480 272C480 320.8 463.2 365.7 435.1 401.1L569 535C578.4 544.4 578.4 558.1 569 567.5C559.6 575.9 544.4 575.9 536 567.5L401.1 435.1z"/></svg>
</button>
</div>
</form> </form>
</SignedIn> </SignedIn>

View File

@@ -46,7 +46,7 @@ import '/src/assets/css/main.scss';
// import 'bootstrap/js/dist/collapse'; // import 'bootstrap/js/dist/collapse';
// import 'bootstrap/js/dist/dropdown'; // import 'bootstrap/js/dist/dropdown';
import 'bootstrap/js/dist/modal'; import 'bootstrap/js/dist/modal';
// import 'bootstrap/js/dist/offcanvas'; import 'bootstrap/js/dist/offcanvas';
// import 'bootstrap/js/dist/popover'; // import 'bootstrap/js/dist/popover';
// import 'bootstrap/js/dist/scrollspy'; // import 'bootstrap/js/dist/scrollspy';
import 'bootstrap/js/dist/tab'; import 'bootstrap/js/dist/tab';

View File

@@ -16,7 +16,7 @@ import { Waitlist as WaitlistAstro } from '@clerk/astro/components'
<div class="col-12 col-md-7"> <div class="col-12 col-md-7">
<h4 class="mt-3">Welcome!</h4> <h4 class="mt-3">Welcome!</h4>
<p class="mt-2"> <p class="mt-2">
This single-page web applictation is currently in a closed beta. Access to the beta will be limited, and the selection process will be highly curated. You are welcome to request access - if you do not get into the beta, don't worry, after the beta is complete, the app will be available to all users.</p> This single-page web application is currently in a closed beta. Access to the beta will be limited, and the selection process will be highly curated. You are welcome to request access - if you do not get into the beta, don't worry, after the beta is complete, the app will be available to all users.</p>
</p> </p>
<p class="my-2"> <p class="my-2">
If you would like to join the waitlist, please enter your email address. You will receive an email with instructions on how to access the app when it becomes available. If you would like to join the waitlist, please enter your email address. You will receive an email with instructions on how to access the app when it becomes available.
@@ -25,7 +25,7 @@ import { Waitlist as WaitlistAstro } from '@clerk/astro/components'
If you aren't interested in joining the waitlist, that is okay too! Feel free to play "Who's that Pokémon?" with the random Pokémon generator <a href="/404">here</a>. Refresh the page to see a new Pokémon! If you aren't interested in joining the waitlist, that is okay too! Feel free to play "Who's that Pokémon?" with the random Pokémon generator <a href="/404">here</a>. Refresh the page to see a new Pokémon!
</p> </p>
</div> </div>
<div class="col-12 col-md-4 offset-md-1 mx-2"> <div class="col-12 col-md-4 offset-md-1">
<WaitlistAstro /> <WaitlistAstro />
</div> </div>
</div> </div>

View File

@@ -66,6 +66,7 @@ const conditionAttributes = (price: any) => {
const current = price?.marketPrice; const current = price?.marketPrice;
const low = price?.lowestPrice; const low = price?.lowestPrice;
const high = price?.highestPrice; const high = price?.highestPrice;
const median = price?.medianPrice;
if (current === null || low === null || high === null) return "—"; if (current === null || low === null || high === null) return "—";
@@ -73,8 +74,8 @@ const conditionAttributes = (price: any) => {
if (range <= 0) return "Low"; if (range <= 0) return "Low";
const position = (Number(current) - Number(low)) / range; const position = (Number(current) - Number(low)) / range;
if (position > 0.75) return "High"; if (position > 0.76) return "High";
if (position > 0.46) return "Medium"; if (position > 0.49) return "Medium";
return "Low"; return "Low";
})(); })();
@@ -103,8 +104,10 @@ const ebaySearchUrl = (card: any) => {
<div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl"> <div class="modal-dialog modal-dialog-centered modal-fullscreen-md-down modal-xl">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header border-0"> <div class="modal-header border-0">
<div class="container-fluid"> <div class="container-fluid row align-items-center">
<span class="h4 card-title pe-2">{card?.productName}</span><span class="text-secondary ps-2 border-start">{card?.number}</span><span class="text-secondary ps-2">{card?.variant}</span> <div class="h4 card-title pe-2 col-sm-12 col-md-auto mb-sm-1">{card?.productName}</div>
<div class="text-secondary border-md-start col-auto">{card?.number}</div>
<div class="text-secondary col-auto">{card?.variant}</div>
</div> </div>
<button type="button" class="btn-close" aria-label="Close" data-bs-dismiss="modal"></button> <button type="button" class="btn-close" aria-label="Close" data-bs-dismiss="modal"></button>
</div> </div>
@@ -113,9 +116,9 @@ const ebaySearchUrl = (card: any) => {
<div class="card mb-2 border-0"> <div class="card mb-2 border-0">
<div class="row g-4"> <div class="row g-4">
<div class="col-sm-12 col-md-3"> <div class="col-sm-12 col-md-3">
<p class="text-secondary">{card?.set?.setName}</p> <div class="position-relative mt-1"><img src={`/cards/${card?.productId}.jpg`} class="card-image w-100 img-fluid rounded-4" alt={card?.productName} onerror="this.onerror=null;this.src='/cards/default.jpg'" onclick="copyImage(this); dataLayer.push({'event': 'copiedImage'});"><span class="position-absolute bottom-0 start-0 d-inline"><SetIcon set={card?.set?.setCode} /></span><span class="position-absolute top-0 end-0 d-inline"><EnergyIcon energy={card?.energyType} /></span><span class="rarity-icon-large position-absolute bottom-0 end-0 d-inline"><RarityIcon rarity={card?.rarityName} /></span></div>
<div class="position-relative"><img src={`/cards/${card?.productId}.jpg`} class="card-image w-100 img-fluid rounded-4" alt={card?.productName} onerror="this.onerror=null;this.src='/cards/default.jpg'" onclick="copyImage(this); dataLayer.push({'event': 'copiedImage'});"><span class="position-absolute bottom-0 start-0 d-inline"><SetIcon set={card?.set?.setCode} /></span><span class="position-absolute top-0 end-0 d-inline"><EnergyIcon energy={card?.energyType} /></span><span class="rarity-icon-large position-absolute bottom-0 end-0 d-inline"><RarityIcon rarity={card?.rarityName} /></span></div>
<div class="d-flex flex-row justify-content-between mt-2"> <div class="d-flex flex-row justify-content-between mt-2">
<div class="p text-secondary">{card?.set?.setName}</div>
<div class="p text-secondary">Illustrator: {card?.Artist}</div> <div class="p text-secondary">Illustrator: {card?.Artist}</div>
</div> </div>
</div> </div>

View File

@@ -123,16 +123,19 @@ if (start === 0) {
{(start === 0) && {(start === 0) &&
<div id="facetContainer" hx-swap-oob="true"> <div id="facetContainer" hx-swap-oob="true">
<button type="submit" form="searchform" class="btn btn-secondary">Apply Filters</button> <div class="bg-dark sticky-top p-2 d-flex justify-content-end align-items-center">
<button type="" form="" class="btn btn-secondary btn-sm me-2">Clear</button>
<button type="submit" form="searchform" class="btn btn-secondary btn-sm">Apply Filters</button>
</div>
{facets.map((facet) => ( {facets.map((facet) => (
<div class="mb-4 facet-group"> <div class="mt-2 mb-4 facet-group row align-items-center justify-content-between">
<div class="h5">{facetNames(facet.field_name)}</div> <div class="h6 m-0 col-auto">{facetNames(facet.field_name)}</div>
{(facet.counts.length > 20) && {(facet.counts.length > 20) &&
<input class="facet-filter" type="text" id={`filter_${facet.field_name}`} placeholder="search..." /> <input class="facet-filter form-control col-auto me-3" type="text" id={`filter_${facet.field_name}`} placeholder="Search..." />
} }
<div class="facet-list"> <div class="facet-list col-11 mt-2">
{facet.counts.map((count) => ( {facet.counts.map((count) => (
<div class="facet-item" data-facet-value={count.value.toLowerCase()}> <div class="facet-item form-check" data-facet-value={count.value.toLowerCase()}>
<label class="form-check-label"> <label class="form-check-label">
<input type="checkbox" name={facet.field_name} value={count.value} checked={filterChecked(facet.field_name, count.value)} class="form-check-input" form="searchform" /> <input type="checkbox" name={facet.field_name} value={count.value} checked={filterChecked(facet.field_name, count.value)} class="form-check-input" form="searchform" />
{count.value} ({count.count}) {count.value} ({count.count})
@@ -142,7 +145,6 @@ if (start === 0) {
</div> </div>
</div> </div>
))} ))}
<button type="submit" form="searchform" class="btn btn-secondary">Apply Filters</button>
</div> </div>
<script define:vars={{ totalHits, filters, facets }} is:inline> <script define:vars={{ totalHits, filters, facets }} is:inline>

View File

@@ -3,7 +3,6 @@ import Layout from '../layouts/Main.astro';
import Search from '../components/Search.astro'; import Search from '../components/Search.astro';
import CardGrid from "../components/CardGrid.astro"; import CardGrid from "../components/CardGrid.astro";
import NavBar from '../components/NavBar.astro'; import NavBar from '../components/NavBar.astro';
import NavItems from '../components/NavItems.astro';
export const prerender = false; export const prerender = false;
--- ---