all repos — emessage @ 4938b2e7cc9504d8085b021945ec49563a3eaa67

The EMessage email client

frontend/src/lib/components/ContactSelector.svelte (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
<script>
	import { global } from "$lib/global.svelte.js";

	let { onselect, exclude } = $props();

	let contacts = $derived(global.contacts.filter(c => c.Emails.length));

	let search = $state("");
	let show = $state(false);

	function searchText(contact) {
		const parts = [
			contact.Firstname,
			contact.Lastname,
			contact.Association,
			contact.Job,
			...contact.Emails.map(e => e.Value),
			...contact.PhoneNumbers.map(p => p.Value),
			...contact.Urls.map(u => u.Value),
			...contact.StreetAddresses.map(s => `${s.Street1} ${s.Street2} ${s.City} ${s.State}`),
			...contact.Dates.map(d => d.Value.slice(0,10)),
			...contact.Other.map(o => o.Value),
		];
		const result = parts.join(" ").toLowerCase();
		return result;
	}
	
	let filtered = $derived(
		search
			? contacts.filter(c => {
				return searchText(c).includes(search.toLowerCase())
			}) : contacts
	);

	let named = $derived(filtered.filter(c => c.Firstname || c.Lastname || c.Association));
	let nameless = $derived(filtered.filter(c => !(c.Firstname || c.Lastname || c.Association)));

	function pick(email) {
		if (onselect) onselect(email);
		show = false;
		search = "";
	}

	function hide() {
		setTimeout(() => { show = false; }, 200);
	}
</script>

<div class="relative">
	<input
		class="w-full bg-header text-primary text-xs border-b-1 border-primary focus:outline-none"
		type="text"
		autofocus
		bind:value={search}
		onfocus={() => (show = true)}
		onblur={hide}/>
	{#if show && filtered.length > 0}
		<ul class="flex flex-col absolute p-2 z-10 w-fit bg-header max-h-60 overflow-y-auto text-xs">
			{#each named as contact}
				<li class="border-b-1 border-primary">
					<div class="px-2 py-1 font-semibold text-primary bg-header">
						{contact.Firstname} {contact.Lastname}
						{#if contact.Association}
							<span class="text-primary">({contact.Association})</span>
						{/if}
					</div>
					{#each contact.Emails as email}
						<button
							class="w-full text-left px-3 py-1 hover:bg-input focus:bg-selected"
							onclick={() => pick(email)}>
							{email.Value} ({email.Key})
						</button>
					{/each}
				</li>
			{/each}
			{#each nameless as contact}
				{#each contact.Emails as email}
					<button
						class="w-full text-left px-3 py-1 hover:bg-input focus:bg-selected"
						onclick={() => pick(email)}>
						{email.Value}
					</button>
				{/each}
			{/each}
		</ul>
	{/if}
</div>