Skip to content

Commit

Permalink
Add progress bar (#1080)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesperengstrom authored Jul 30, 2024
1 parent b350e1d commit 0d43d02
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 153 deletions.
7 changes: 7 additions & 0 deletions lxl-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lxl-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"lxljs": "file:../lxljs",
"magic-string": "^0.30.7",
"mdsvex": "^0.11.2",
"nprogress": "^0.2.0",
"postcss": "^8.4.38",
"postcss-import": "^16.1.0",
"prettier": "^3.3.2",
Expand Down
1 change: 1 addition & 0 deletions lxl-web/src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ declare module 'lxljs/data';
declare module 'lxljs/display';
declare module 'lxljs/string';
declare module 'lxljs/vocab';
declare module 'nprogress';
271 changes: 133 additions & 138 deletions lxl-web/src/lib/components/find/SearchResult.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import SearchCard from './SearchCard.svelte';
import Pagination from './Pagination.svelte';
import Filters from './Filters.svelte';
import SearchRelated from './SearchRelated.svelte';
import IconSliders from '~icons/bi/sliders';
import BiChevronDown from '~icons/bi/chevron-down';
import type { SearchResult, DisplayMapping } from '$lib/types/search';
import { shouldShowMapping } from '$lib/utils/search';
import SearchRelated from './SearchRelated.svelte';
let showFiltersModal = false;
export let searchResult: SearchResult;
Expand Down Expand Up @@ -48,154 +48,149 @@

<slot />
{#if searchResult}
{#await searchResult}
<p class="p-4">{$page.data.t('search.loading')}</p>
{:then searchResult}
{#if searchResult}
{@const facets = searchResult.facetGroups}
{@const numHits = searchResult.totalItems}
{@const filterCount = getFiltersCount(searchResult.mapping)}
{#if searchResult.predicates.length > 0}
<nav
class="border-b border-primary/16 px-4 md:flex lg:px-6"
aria-label={$page.data.t('search.selectedFilters')}
>
<ul class="flex flex-wrap items-center gap-2">
<li class="tab-header max-w-80 truncate font-bold">{$page.data.title}</li>
<span class="tab-header">{$page.data.t('search.occursAs')}</span>
{@const facets = searchResult.facetGroups}
{@const numHits = searchResult.totalItems}
{@const filterCount = getFiltersCount(searchResult.mapping)}
{#if searchResult.predicates.length > 0}
<nav
class="border-b border-primary/16 px-4 md:flex lg:px-6"
aria-label={$page.data.t('search.selectedFilters')}
>
<ul class="flex flex-wrap items-center gap-2">
<li class="tab-header max-w-80 truncate font-bold">{$page.data.title}</li>
<span class="tab-header">{$page.data.t('search.occursAs')}</span>

{#each searchResult.predicates as p}
<li>
<a
class="tab"
class:active={true}
class:tab-selected={p.selected}
data-sveltekit-replacestate
href={p.view['@id']}
>
{p.str}
<span
class="mb-px rounded-sm bg-pill/4 px-1 text-sm text-secondary md:text-xs lg:text-sm"
aria-label="{p.totalItems} {$page.data.t('search.hits')}">{p.totalItems}</span
>
</a>
</li>
{/each}
</ul>
</nav>
{/if}
{#if shouldShowMapping(searchResult.mapping)}
<nav
class="hidden md:flex md:px-6 md:pb-0 md:pt-4"
aria-label={$page.data.t('search.selectedFilters')}
{#each searchResult.predicates as p}
<li>
<a
class="tab"
class:active={true}
class:tab-selected={p.selected}
data-sveltekit-replacestate
href={p.view['@id']}
>
{p.str}
<span
class="mb-px rounded-sm bg-pill/4 px-1 text-sm text-secondary md:text-xs lg:text-sm"
aria-label="{p.totalItems} {$page.data.t('search.hits')}">{p.totalItems}</span
>
</a>
</li>
{/each}
</ul>
</nav>
{/if}
{#if shouldShowMapping(searchResult.mapping)}
<nav
class="hidden md:flex md:px-6 md:pb-0 md:pt-4"
aria-label={$page.data.t('search.selectedFilters')}
>
<SearchMapping mapping={searchResult.mapping} />
</nav>
{/if}
<div class="relative gap-y-4 find-layout md:page-padding">
{#if showFiltersModal}
<Modal position="left" close={toggleFiltersModal}>
<span slot="title">
{$page.data.t('search.filters')} ({numHits.toLocaleString($page.data.locale)}
{numHits == 1 ? $page.data.t('search.hitsOne') : $page.data.t('search.hits')})
</span>
<Filters {facets} mapping={searchResult.mapping} />
</Modal>
{/if}
<div class="filters hidden md:block" id="filters">
<Filters {facets} mapping={searchResult.mapping} />
</div>

<div class="results max-w-content">
<div
class="toolbar flex min-h-14 items-center justify-between page-padding md:min-h-fit md:p-0 md:pb-4"
class:has-search={$page.params.fnurgel}
>
<a
href={`${$page.url.pathname}?${$page.url.searchParams.toString()}#filters`}
class="filter-modal-toggle button-ghost md:hidden"
aria-label={$page.data.t('search.filters')}
on:click|preventDefault={toggleFiltersModal}
>
<SearchMapping mapping={searchResult.mapping} />
</nav>
{/if}
<div class="relative gap-y-4 find-layout md:page-padding">
{#if showFiltersModal}
<Modal position="left" close={toggleFiltersModal}>
<span slot="title">
{$page.data.t('search.filters')} ({numHits.toLocaleString($page.data.locale)}
{numHits == 1 ? $page.data.t('search.hitsOne') : $page.data.t('search.hits')})
<IconSliders width={20} height={20} />
{$page.data.t('search.filters')}
{#if filterCount}
<span
class="flex h-5 w-5 items-center justify-center rounded-full bg-pill text-xs font-bold leading-none text-primary-inv"
>
{filterCount}
</span>
<Filters {facets} mapping={searchResult.mapping} />
</Modal>
{/if}
<div class="filters hidden md:block" id="filters">
<Filters {facets} mapping={searchResult.mapping} />
{/if}
</a>
<span class="hits pt-4 text-secondary md:pt-0" role="status" data-testid="result-info">
{#if numHits && numHits > 0}
{#if numHits > searchResult.itemsPerPage}
<span class="text-3-cond-bold">
{(searchResult.itemOffset + 1).toLocaleString($page.data.locale)}
-
{Math.min(
numHits,
searchResult.itemOffset + searchResult.itemsPerPage
).toLocaleString($page.data.locale)}
</span>
{$page.data.t('search.hitsOf')}
{/if}
<span class="text-3-cond-bold">
{numHits.toLocaleString($page.data.locale)}
</span>
{#if $page.data.instances}
{numHits == 1
? $page.data.t('search.relatedOne')
: $page.data.t('search.related')}
{/if}
{numHits == 1 ? $page.data.t('search.hitsOne') : $page.data.t('search.hits')}
{:else}
{$page.data.t('search.noResults')}
{/if}
</span>
<div class="search-related flex justify-start">
{#if $page.params.fnurgel}
{@const activePredicate = searchResult.predicates.filter((p) => p.selected)}
<SearchRelated view={activePredicate[0].view} />
{/if}
</div>

<div class="results max-w-content">
{#if numHits > 0}
<div
class="toolbar flex min-h-14 items-center justify-between page-padding md:min-h-fit md:p-0 md:pb-4"
class:has-search={$page.params.fnurgel}
class="sort-select flex flex-col items-end justify-self-end"
data-testid="sort-select"
>
<a
href={`${$page.url.pathname}?${$page.url.searchParams.toString()}#filters`}
class="filter-modal-toggle button-ghost md:hidden"
aria-label={$page.data.t('search.filters')}
on:click|preventDefault={toggleFiltersModal}
>
<IconSliders width={20} height={20} />
{$page.data.t('search.filters')}
{#if filterCount}
<span
class="flex h-5 w-5 items-center justify-center rounded-full bg-pill text-xs font-bold leading-none text-primary-inv"
>
{filterCount}
</span>
{/if}
</a>
<span class="hits pt-4 text-secondary md:pt-0" role="status" data-testid="result-info">
{#if numHits && numHits > 0}
{#if numHits > searchResult.itemsPerPage}
<span class="text-3-cond-bold">
{(searchResult.itemOffset + 1).toLocaleString($page.data.locale)}
-
{Math.min(
numHits,
searchResult.itemOffset + searchResult.itemsPerPage
).toLocaleString($page.data.locale)}
</span>
{$page.data.t('search.hitsOf')}
{/if}
<span class="text-3-cond-bold">
{numHits.toLocaleString($page.data.locale)}
</span>
{#if $page.data.instances}
{numHits == 1
? $page.data.t('search.relatedOne')
: $page.data.t('search.related')}
{/if}
{numHits == 1 ? $page.data.t('search.hitsOne') : $page.data.t('search.hits')}
{:else}
{$page.data.t('search.noResults')}
{/if}
</span>
<div class="search-related flex justify-start">
{#if $page.params.fnurgel}
{@const activePredicate = searchResult.predicates.filter((p) => p.selected)}
<SearchRelated view={activePredicate[0].view} />
{/if}
<label class="pr-6 text-secondary text-2-regular" for="search-sort">
{$page.data.t('sort.sort')}
</label>
<div class="relative">
<select id="search-sort" form="main-search" on:change={handleSortChange}>
{#each sortOptions as option}
<option value={option.value} selected={option.value === sortOrder}
>{option.label}</option
>
{/each}
</select>
<span class="pointer-events-none absolute right-0 top-[5px]">
<BiChevronDown aria-hidden="true" class="text-icon" />
</span>
</div>
{#if numHits > 0}
<div
class="sort-select flex flex-col items-end justify-self-end"
data-testid="sort-select"
>
<label class="pr-6 text-secondary text-2-regular" for="search-sort">
{$page.data.t('sort.sort')}
</label>
<div class="relative">
<select id="search-sort" form="main-search" on:change={handleSortChange}>
{#each sortOptions as option}
<option value={option.value} selected={option.value === sortOrder}
>{option.label}</option
>
{/each}
</select>
<span class="pointer-events-none absolute right-0 top-[5px]">
<BiChevronDown aria-hidden="true" class="text-icon" />
</span>
</div>
</div>
{/if}
</div>
<ol class="flex flex-col gap-0.5 md:px-0">
{#each searchResult.items as item (item['@id'])}
<li>
<SearchCard {item} />
</li>
{/each}
</ol>
<Pagination data={searchResult} />
</div>
{/if}
</div>
{/if}
{/await}
<ol class="flex flex-col gap-0.5 md:px-0">
{#each searchResult.items as item (item['@id'])}
<li>
<SearchCard {item} />
</li>
{/each}
</ol>
<Pagination data={searchResult} />
</div>
</div>
{/if}


<style lang="postcss">
.toolbar {
@apply grid;
Expand Down
30 changes: 30 additions & 0 deletions lxl-web/src/nprogress.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* Make clicks pass-through */
#nprogress {
pointer-events: none;
}

#nprogress .bar {
@apply bg-positive-dark;

position: fixed;
z-index: 1031;
top: 0;
left: 0;
width: 100%;
height: 2px;
}

/* Fancy blur effect */
#nprogress .peg {
display: block;
position: absolute;
right: 0px;
width: 100px;
height: 100%;
box-shadow: 0 0 10px #6e6e6e, 0 0 5px #6e6e6e;
opacity: 1.0;

-webkit-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
Loading

0 comments on commit 0d43d02

Please sign in to comment.