commit
2bb2d07653
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* @param {rating[]} ratings An array of ratings
|
||||
* @returns {number} Average rating
|
||||
*/
|
||||
export const getAvgRating = (ratings) => {
|
||||
if (!ratings) return 0;
|
||||
if (ratings.length === 1) return ratings[0].rating;
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
/**
|
||||
* @param {string} str Any string
|
||||
* @returns {string} Lowercased string without any extra spaces
|
||||
*/
|
||||
export const normalize = (str) => str.toLowerCase().trim()
|
||||
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import {normalize }from './normalize';
|
||||
|
||||
/**
|
||||
* @param {string} slug Slug of a product name
|
||||
* @returns Normalized slug with all dashes replaced with spaces
|
||||
*/
|
||||
export function parseSlug(slug) {
|
||||
return normalize(slug).replaceAll("-", " ")
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name Product name
|
||||
* @returns Normalized name with all spaces replaced with '-'
|
||||
*/
|
||||
export function parseName(name) {
|
||||
return normalize(name).replaceAll(" ","-")
|
||||
}
|
|
@ -1,8 +1,35 @@
|
|||
import {normalize, parseName} from './index';
|
||||
import { parseName, parseSlug, normalize } from './';
|
||||
|
||||
export const toProduct = (product, currentProduct) => {
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.set('product', normalize(parseName(product.name)));
|
||||
window.history.pushState({}, '', url);
|
||||
currentProduct.set(product)
|
||||
}
|
||||
/**
|
||||
* Updates a url with search parameters to match product name of product passed in.
|
||||
* @param {URL} url a URL object
|
||||
* @param {object} product
|
||||
* @returns {URL} a URL object with search parameters appended.
|
||||
*/
|
||||
const setUrlParam = (url, product) => {
|
||||
url.searchParams.set('product', parseName(product.name));
|
||||
return url;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates Window URL and checks that it is equal to product name
|
||||
* @param {URL} url a URL object
|
||||
* @param {product} product product to check URL against
|
||||
* @returns {Boolean} True if URL parameter is equal to product name
|
||||
*/
|
||||
const didWinUrlUpdate = (url, product) => {
|
||||
window.history.pushState(window.history.state, '', url);
|
||||
const params = new URLSearchParams(window.location.search).get('product');
|
||||
return parseSlug(params) === normalize(product.name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a `product` and `currentProduct` store
|
||||
* Sets URL params to parsed product name and updates Browser URL
|
||||
* Sets `currentProduct` store to `product`.
|
||||
* @param {object} product The product to switch feature to.
|
||||
* @param {store} currentProduct currentProduct store
|
||||
*/
|
||||
export const toProduct = (product, currentProduct) =>
|
||||
didWinUrlUpdate(setUrlParam(new URL(window.location), product), product) &&
|
||||
currentProduct.set(product)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { urlFor } from '$lib/sanityClient';
|
||||
import { currentProduct } from '$lib/stores';
|
||||
import Rating from './Rating/Rating.svelte';
|
||||
import PrevNext from './PrevNext/PrevNext.svelte';
|
||||
import Tag from './Tag/Tag.svelte';
|
||||
|
||||
const { container, imageView, name, description, productInfo, date, tags, img, ratings } = {
|
||||
|
@ -44,6 +45,7 @@
|
|||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<PrevNext />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<script>
|
||||
import { currentProduct, productsView } from '$lib/stores';
|
||||
import { toProduct } from '$helpers';
|
||||
|
||||
$: foundIndex = $productsView.findIndex((prod) => prod._id === $currentProduct._id)
|
||||
$: PREV = $productsView[foundIndex-1];
|
||||
$: NEXT = $productsView[foundIndex+1];
|
||||
|
||||
const navigate = (e) => {
|
||||
if (e.target.name === 'prev' && PREV) {
|
||||
toProduct(PREV, currentProduct)
|
||||
}
|
||||
if (e.target.name === 'next' && NEXT){
|
||||
toProduct(NEXT, currentProduct)
|
||||
}
|
||||
}
|
||||
|
||||
const { container, btn } = {
|
||||
container: 'flex justify-between h-12 ml-16 mr-16',
|
||||
btn: 'flex items-center gap-4'
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class={container}>
|
||||
{#if PREV }
|
||||
<button on:click={navigate} class={btn} name={'prev'}
|
||||
><svg focusable="false" width={50} height={50} viewBox="0 0 24 24">
|
||||
<path d="m14 7-5 5 5 5V7z" />
|
||||
</svg>{PREV.name}</button
|
||||
>
|
||||
{:else}
|
||||
<div></div>
|
||||
{/if}
|
||||
|
||||
{#if NEXT}
|
||||
<button on:click={navigate} class={btn} name={'next'}
|
||||
>{NEXT.name}<svg focusable="false" width={50} height={50} viewBox="0 0 24 24"
|
||||
><path d="m10 17 5-5-5-5v10z" /></svg
|
||||
></button
|
||||
>
|
||||
{:else}
|
||||
<div></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
svg,path {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
productsView.set(data.products);
|
||||
const goToProduct = () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const paramProd = params.get('product');
|
||||
const paramProd = (new URLSearchParams(window.location.search)).get('product');
|
||||
|
||||
if (paramProd) {
|
||||
const foundProduct = $products.find(
|
||||
|
|
|
@ -3,7 +3,7 @@ import { resolve } from 'path';
|
|||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
const config = {
|
||||
plugins: [sveltekit()],
|
||||
plugins: [sveltekit()],
|
||||
resolve: {
|
||||
alias: {
|
||||
$lib: resolve('./src/lib'),
|
||||
|
|
Loading…
Reference in New Issue