Skip to content

Commit

Permalink
feat: Merge categories/tags and improve filtering (#541)
Browse files Browse the repository at this point in the history
* Experiment with SSR and query params

* Require all tags to be present

* Fix when no query param present

* Add tag links

* Working add/remove tags

* Fix templates route

* Remove old category/tags selectors

* Button style

* More styling

* Remove unused code

* Remove @sindresorhus/slugify

* Format and disable prerender

* Improve css grid

* Use searchParams.getAll

* Replace itemsjs with filter/sort functions

* Always show selected tags

* Add data-sveltekit-noscroll

* Move sortableFields to prop level

* Simplify code

* Fix sortArray for dates

* Add an icon to clear filters

* Convert tags to kebab-case

* Add category to tags

* Delete category field

* Remove duplicated tags

* Merge more tags
  • Loading branch information
lachlancollins authored Dec 30, 2023
1 parent 54114c2 commit 11d5ed5
Show file tree
Hide file tree
Showing 17 changed files with 892 additions and 1,333 deletions.
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@
},
"devDependencies": {
"@macfja/svelte-persistent-store": "2.4.1",
"@sindresorhus/slugify": "^2.2.1",
"@sveltejs/adapter-auto": "^3.0.1",
"@sveltejs/kit": "^2.0.1",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@types/eslint": "^8.44.9",
"@types/itemsjs": "^2.1.6",
"@types/node": "^20.10.5",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
Expand All @@ -31,7 +29,6 @@
"eslint-plugin-svelte": "^2.35.1",
"get-npm-tarball-url": "^2.1.0",
"highlight.js": "^11.9.0",
"itemsjs": "^2.1.24",
"mdsvex": "^0.11.0",
"package-name-regex": "^3.1.1",
"pako": "^2.1.0",
Expand Down
37 changes: 0 additions & 37 deletions pnpm-lock.yaml

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

152 changes: 63 additions & 89 deletions src/lib/SearchableJson.svelte
Original file line number Diff line number Diff line change
@@ -1,106 +1,87 @@
<script lang="ts">
import slugify from '@sindresorhus/slugify';
import ComponentCard from '$lib/components/ComponentIndex/Card.svelte';
import CardList from '$lib/components/ComponentIndex/CardList.svelte';
import SearchLayout from '$layouts/SearchLayout.svelte';
import { extractUnique } from '$lib/utils/extractUnique';
import Seo from '$lib/components/Seo.svelte';
import Search from '$lib/components/Search.svelte';
import Select from '$lib/components/Select.svelte';
import { packageManager } from '$stores/packageManager';
import TagFilters from '$lib/TagFilters.svelte';
import { filterArray, sortArray } from '$utils/arrayUtils';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export let data: any[];
export let tags: string[];
export let selectedTags: string[];
export let sortableFields: { value: string; label: string; asc: boolean }[];
export let displayTitle = '';
export let displayTitleSingular = '';
export let submittingType = '';
const sortableFields = [
{ identifier: 'stars', title: 'Stars', ascending: false },
{ identifier: 'title', title: 'Name', ascending: true },
{ identifier: 'date', title: 'Date', ascending: false }
];
let searchValue: string;
let sort = sortableFields[0];
const dataDefault = { category: '' };
$: dataToDisplay = data.map((line) => ({ ...dataDefault, ...line }));
$: categories = extractUnique(dataToDisplay, 'category');
$: filteredData = filterArray(data, searchValue);
$: sortedData = sortArray(filteredData, sort);
</script>

<Seo title={displayTitle} />

<SearchLayout title={displayTitle}>
<section slot="controls" class="controls">
<div class="inputs">
<Search
data={dataToDisplay}
bind:query={searchValue}
{sortableFields}
searchableFields={['title', 'description']}
facetsConfig={[
{
title: 'Category',
identifier: 'category'
},
{
title: 'Tags',
identifier: 'tags',
isMulti: true
}
]}
on:search={(a) => (dataToDisplay = a.detail.data.items)}
/>
<Select
label="Package manager"
isClearable={false}
isSearchable={false}
showIndicator
value={{ value: $packageManager }}
on:select={({ detail }) => ($packageManager = detail.value)}
items={[
{ label: 'NPM', value: 'npm' },
{ label: 'PNPM', value: 'pnpm' },
{ label: 'Yarn', value: 'yarn' }
]}
/>
<a href="/help/submitting?type={submittingType}" class="submit"
>Submit a {displayTitleSingular}</a
>
</div>
<h1>{displayTitle}</h1>

<input
class="searchbar"
type="text"
placeholder="Search for {displayTitle.toLowerCase()}..."
bind:value={searchValue}
<TagFilters {tags} {selectedTags} />
<br />
<section class="controls">
<input
class="searchbar"
type="text"
placeholder="Search for {displayTitle.toLowerCase()}..."
bind:value={searchValue}
/>
<div class="inputs">
<Select
items={sortableFields}
bind:value={sort}
label="Sorting"
showIndicator
isClearable={false}
/>
<span class="searchbar-count"
>{dataToDisplay.length} result{#if dataToDisplay.length !== 1}s{/if}</span
<Select
label="Package manager"
isClearable={false}
isSearchable={false}
showIndicator
value={{ value: $packageManager }}
on:select={({ detail }) => ($packageManager = detail.value)}
items={[
{ label: 'NPM', value: 'npm' },
{ label: 'PNPM', value: 'pnpm' },
{ label: 'Yarn', value: 'yarn' }
]}
/>
<a href="/help/submitting?type={submittingType}" class="submit"
>Submit a {displayTitleSingular}</a
>
</section>
<section slot="items">
{#each categories as category}
<CardList title={category.label} id={slugify(category.label)}>
{#each dataToDisplay.filter((d) => d.category === category.value || (!categories
.map((v) => v.value)
.includes(d.category) && category.value === '')) as entry (entry.title)}
<ComponentCard
title={entry.title}
description={entry.description}
repository={entry.repository}
stars={entry.stars}
tags={entry.tags}
date={entry.date}
npm={entry.npm}
version={entry.version}
/>
{/each}
</CardList>
</div>
<span class="searchbar-count"
>{data.length} result{#if data.length !== 1}s{/if}</span
>
</section>
<hr />
<section>
<CardList>
{#each sortedData as entry (entry.title)}
<ComponentCard
title={entry.title}
description={entry.description}
repository={entry.repository}
stars={entry.stars}
tags={entry.tags}
date={entry.date}
npm={entry.npm}
version={entry.version}
/>
{/each}
</section>
</SearchLayout>
</CardList>
</section>

<style>
.controls {
Expand All @@ -119,7 +100,6 @@
padding: 20.5px var(--s-2);
border: 2px solid var(--dark-gray);
border-radius: 2px;
align-self: flex-end;
grid-row: 1/2;
font-family: Overpass;
background: #f3f6f9 url(/images/search-icon.svg) 98% no-repeat;
Expand All @@ -135,15 +115,9 @@
right: 0;
}
@media (min-width: 1280px) {
.controls {
grid-template-columns: 2fr 1fr;
}
@media (min-width: 1024px) {
.inputs {
grid-template-columns: repeat(4, auto);
}
.searchbar {
grid-row: auto;
grid-template-columns: repeat(2, auto);
}
}
</style>
68 changes: 68 additions & 0 deletions src/lib/TagFilters.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script lang="ts">
import { page } from '$app/stores';
import Icon from '$lib/components/Icon/index.svelte';
export let tags: string[];
export let selectedTags: string[];
</script>

<div data-sveltekit-noscroll>
{#each selectedTags as tag}
{@const newTags = selectedTags.filter((t) => t !== tag)}
{@const title = tag.replaceAll('-', ' ')}
{#if newTags.length === 0}
<a class="tag active" href={$page.url.pathname}>{title}</a>
{:else}
<a
class="tag active"
href={`${$page.url.pathname}?${newTags.map((t) => `tag=${t}`).join('&')}`}
>
{title}
</a>
{/if}
{/each}

{#each tags as tag}
{#if !selectedTags.includes(tag)}
{@const newTags = [...selectedTags, tag]}
{@const title = tag.replaceAll('-', ' ')}
<a class="tag" href={`${$page.url.pathname}?${newTags.map((t) => `tag=${t}`).join('&')}`}>
{title}
</a>
{/if}
{/each}

{#if selectedTags.length !== 0}
<a href={$page.url.pathname}><Icon name="close" /></a>
{/if}
</div>

<style>
div {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
}
a {
border: none;
}
.tag {
padding: 4px 12px;
border: 1px solid var(--link-color);
border-radius: 9999px;
font-family: Overpass;
font-style: normal;
font-weight: normal;
font-size: 14px;
line-height: 150%;
text-align: center;
}
.active {
color: #ff3e01;
background: #ffdbcf;
}
</style>
13 changes: 0 additions & 13 deletions src/lib/components/ComponentIndex/CardList.svelte
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
<script lang="ts">
export let title: string;
export let id = `category-${title}`;
</script>

<div class="list">
<h1 {id}>{title} <a href="#{id}">#</a></h1>
<div class="grid">
<slot />
</div>
</div>

<style>
h1 {
font-family: Overpass;
font-style: normal;
font-weight: 600;
line-height: 150%;
margin-bottom: 1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
Expand Down
Loading

0 comments on commit 11d5ed5

Please sign in to comment.