mirror of
https://github.com/catdevnull/preciazo.git
synced 2024-11-22 06:16:18 +00:00
parent
e96bf8dc74
commit
0be2ff8911
7 changed files with 92 additions and 36 deletions
17
sepa/sitio2/src/lib/components/Loading.svelte
Normal file
17
sepa/sitio2/src/lib/components/Loading.svelte
Normal file
|
@ -0,0 +1,17 @@
|
|||
<script lang="ts">
|
||||
// Parent has to be position relative
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
|
||||
export let loading = false;
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<LoaderCircle class="h-4 w-4 animate-spin" />
|
||||
</div>
|
||||
<div class="invisible">
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
|
@ -1,17 +1,25 @@
|
|||
<script lang="ts">
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { goto } from '$app/navigation';
|
||||
import { afterNavigate, beforeNavigate, goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
let search = $page.params.query ?? '';
|
||||
|
||||
let loading = false;
|
||||
beforeNavigate(() => {
|
||||
loading = true;
|
||||
});
|
||||
afterNavigate(() => {
|
||||
loading = false;
|
||||
});
|
||||
|
||||
function handleSubmit() {
|
||||
goto(`/search/${encodeURIComponent(search)}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="flex gap-2" on:submit|preventDefault={handleSubmit}>
|
||||
<Input placeholder="Buscar productos" bind:value={search} />
|
||||
<Button type="submit">Buscar</Button>
|
||||
<Input placeholder="Buscar productos" bind:value={search} disabled={loading} />
|
||||
<Button type="submit" {loading}>Buscar</Button>
|
||||
</form>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { Button as ButtonPrimitive } from 'bits-ui';
|
||||
import { type Events, type Props, buttonVariants } from './index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import Loading from '$lib/components/Loading.svelte';
|
||||
|
||||
type $$Props = Props;
|
||||
type $$Events = Events;
|
||||
|
@ -10,16 +11,19 @@
|
|||
export let variant: $$Props['variant'] = 'default';
|
||||
export let size: $$Props['size'] = 'default';
|
||||
export let builders: $$Props['builders'] = [];
|
||||
export let loading = false;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<ButtonPrimitive.Root
|
||||
{builders}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
class={cn(buttonVariants({ variant, size, className }), 'relative')}
|
||||
type="button"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<Loading {loading}>
|
||||
<slot />
|
||||
</Loading>
|
||||
</ButtonPrimitive.Root>
|
||||
|
|
|
@ -32,6 +32,7 @@ type Size = VariantProps<typeof buttonVariants>['size'];
|
|||
type Props = ButtonPrimitive.Props & {
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
loading?: boolean;
|
||||
};
|
||||
|
||||
type Events = ButtonPrimitive.Events;
|
||||
|
|
|
@ -28,3 +28,14 @@ export const pesosFormatter = new Intl.NumberFormat('es-AR', {
|
|||
style: 'currency',
|
||||
currency: 'ARS'
|
||||
});
|
||||
|
||||
export function parseMarcas(marcas: readonly string[]) {
|
||||
const x = marcas
|
||||
.map((m) => m.trim().replaceAll(/['`´]/g, ''))
|
||||
.filter((m) => !['sin marca', 'VARIOS'].includes(m))
|
||||
.filter((m) => m.length > 0);
|
||||
if (x.length === 0) {
|
||||
return ['n/a'];
|
||||
}
|
||||
return Array.from(new Set(x));
|
||||
}
|
||||
|
|
|
@ -6,19 +6,9 @@
|
|||
import { ArrowLeft } from 'lucide-svelte';
|
||||
import type { PageData } from './$types';
|
||||
import { goto } from '$app/navigation';
|
||||
import ProductCard from './ProductCard.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
function parseMarcas(marcas: readonly string[]) {
|
||||
const x = marcas
|
||||
.map((m) => m.trim().replaceAll(/['`´]/g, ''))
|
||||
.filter((m) => !['sin marca', 'VARIOS'].includes(m))
|
||||
.filter((m) => m.length > 0);
|
||||
if (x.length === 0) {
|
||||
return ['n/a'];
|
||||
}
|
||||
return Array.from(new Set(x));
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -39,26 +29,7 @@
|
|||
</p>
|
||||
{:else}
|
||||
{#each data.collapsedProductos as producto}
|
||||
<a href={`/id_producto/${producto.id_producto}`} class="my-2 block">
|
||||
<Card.Root class="transition-colors duration-200 hover:bg-gray-100">
|
||||
<Card.Header class="block px-3 py-2 pb-0">
|
||||
<Badge>{parseMarcas(Array.from(producto.marcas)).join('/')}</Badge>
|
||||
<Badge variant="outline"
|
||||
>en
|
||||
{producto.in_datasets_count} cadena{#if producto.in_datasets_count > 1}s{/if}
|
||||
</Badge>
|
||||
<Badge variant="outline">EAN {producto.id_producto}</Badge>
|
||||
</Card.Header>
|
||||
<Card.Content class="px-3 py-2">
|
||||
{#each producto.descriptions as description}
|
||||
<span>{description}</span>
|
||||
{#if description !== producto.descriptions[producto.descriptions.length - 1]}
|
||||
<span class="text-gray-500">⋅</span>{' '}
|
||||
{/if}
|
||||
{/each}
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</a>
|
||||
<ProductCard {producto} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
44
sepa/sitio2/src/routes/search/[query]/ProductCard.svelte
Normal file
44
sepa/sitio2/src/routes/search/[query]/ProductCard.svelte
Normal file
|
@ -0,0 +1,44 @@
|
|||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
import { parseMarcas } from '$lib/sepa-utils';
|
||||
import { beforeNavigate } from '$app/navigation';
|
||||
import Loading from '$lib/components/Loading.svelte';
|
||||
|
||||
export let producto: {
|
||||
id_producto: string;
|
||||
marcas: string[];
|
||||
in_datasets_count: number;
|
||||
descriptions: string[];
|
||||
};
|
||||
|
||||
let loading = false;
|
||||
beforeNavigate((x) => {
|
||||
if (x.to?.params?.id === producto.id_producto) {
|
||||
loading = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<a href={`/id_producto/${producto.id_producto}`} class="my-2 block">
|
||||
<Card.Root class="relative transition-colors duration-200 hover:bg-gray-100">
|
||||
<Loading {loading}>
|
||||
<Card.Header class="block px-3 py-2 pb-0">
|
||||
<Badge>{parseMarcas(Array.from(producto.marcas)).join('/')}</Badge>
|
||||
<Badge variant="outline"
|
||||
>en
|
||||
{producto.in_datasets_count} cadena{#if producto.in_datasets_count > 1}s{/if}
|
||||
</Badge>
|
||||
<Badge variant="outline">EAN {producto.id_producto}</Badge>
|
||||
</Card.Header>
|
||||
<Card.Content class="px-3 py-2">
|
||||
{#each producto.descriptions as description}
|
||||
<span>{description}</span>
|
||||
{#if description !== producto.descriptions[producto.descriptions.length - 1]}
|
||||
<span class="text-gray-500">⋅</span>{' '}
|
||||
{/if}
|
||||
{/each}
|
||||
</Card.Content>
|
||||
</Loading>
|
||||
</Card.Root>
|
||||
</a>
|
Loading…
Reference in a new issue