146 lines
No EOL
5.2 KiB
Svelte
146 lines
No EOL
5.2 KiB
Svelte
<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} |