<script lang="ts"> import type { Entry as EntryType, EntryKind, KnownFeeling } from "$lib/entry"; import ExternalLink from "./utils/ExternalLink.svelte"; import FeelingPill from "./utils/FeelingPill.svelte"; import Entry from "./utils/Entry.svelte"; import EntryDescription from "./utils/EntryDescription.svelte"; import AssetPreview from "./utils/AssetPreview.svelte"; import { createEventDispatcher } from "svelte"; import Fuse from "fuse.js"; let dispatch = createEventDispatcher() export let entries: EntryType[] let filteredEntries = entries export let filters: { fromDate: null | Date, toDate: null | Date, kind: null | EntryKind[], feelings: null | { exclusive: boolean, feelings: KnownFeeling[], }, searchQuery: null | string, } let extended: string[] = [] function applyFilters(filters: { fromDate: null | Date, toDate: null | Date, kind: null | EntryKind[], feelings: null | { exclusive: boolean, feelings: KnownFeeling[], }, searchQuery: null | string, }) { filteredEntries = entries if (filters.fromDate != null) { filteredEntries = entries.filter((v) => new Date(v.creationDate) >= filters.fromDate!); } if (filters.toDate != null) { filteredEntries = entries.filter((v) => new Date(v.creationDate) <= filters.toDate!); } if (filters.kind != null) { filteredEntries = entries.filter((v) => filters.kind!.includes(v.base.kind)); } if (filters.feelings != null) { let feelings = filters.feelings!.feelings if (filters.feelings.exclusive) { filteredEntries = entries.filter((v) => { let v1 = v.feelings.filter((f) => typeof f === "string" && feelings.includes(f)) return v.feelings.length === v1.length; }) } else { filteredEntries = entries.filter((v) => { let includes = false feelings.forEach((f) => { if (v.feelings.includes(f)) { includes = true } }) return includes }) } } if (filters.searchQuery != null) { let fuse = new Fuse(entries, { keys: [ "title", "description", ], }); let results = fuse.search(filters.searchQuery!); filteredEntries = results.map((v) => v.item); } if (filteredEntries.length !== entries.length) { dispatch('updatedFilterStatus', true) } else { dispatch('updatedFilterStatus', false) } } $: applyFilters(filters) </script> {#each filteredEntries as entry (entry.id)} <Entry on:extended={(e) => extended = [e.detail.id, ...extended]} on:contracted={(e) => extended = extended.filter(v => v !== e.detail.id)} on:deleted={(e) => { dispatch('deleted', e.detail) }} id={entry.id} kind={entry.base.kind} creationDate={new Date(entry.creationDate)} title={entry.base.kind === "date" ? new Date(entry.base.referencedDate).toLocaleDateString() : entry.title} isExtended={extended.includes(entry.id)} > <div slot="contracted"> {#if entry.base.kind === "song" || entry.base.kind === "album"} <ExternalLink href={entry.base.link[0]}>{entry.base.artist} ‐ {entry.base.title}</ExternalLink> {/if} {#if entry.base.kind === "feeling"} <div class="flex gap-1"> {#each entry.feelings as feeling} {#if typeof feeling === "string"} <FeelingPill feeling={feeling}/> {:else} <FeelingPill feeling={feeling.identifier} bgColor={feeling.backgroundColor} textColor={feeling.textColor}/> {/if} {/each} </div> {/if} </div> <div slot="extended"> <div class="flex gap-1 mb-2"> {#each entry.feelings as feeling} {#if typeof feeling === "string"} <FeelingPill feeling={feeling}/> {:else} <FeelingPill feeling={feeling.identifier} bgColor={feeling.backgroundColor} textColor={feeling.textColor}/> {/if} {/each} </div> {#if entry.base.kind === "song" || entry.base.kind === "album"} <ExternalLink href={entry.base.link[0]}>{entry.base.artist} ‐ {entry.base.title}</ExternalLink> {/if} {#if entry.description != null} <EntryDescription>{entry.description}</EntryDescription> {/if} <div class="flex gap-1 mt-2"> {#each entry.assets as asset} <AssetPreview asset_id={asset}/> {/each} </div> </div> </Entry> {/each}