107 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
| <script lang="ts">
 | |
| 	import { ApplicationStatusMaping, type Application } from '$lib/ApplicationsStore.svelte';
 | |
| 	import { post } from '$lib/utils';
 | |
| 
 | |
| 	let {
 | |
| 		application,
 | |
| 		onreload
 | |
| 	}: {
 | |
| 		application?: Application;
 | |
| 		onreload: (item: Application) => void;
 | |
| 	} = $props();
 | |
| 
 | |
| 	let filter = $state('');
 | |
| 	let applications: Application[] = $state([]);
 | |
| 
 | |
| 	let dialogElement: HTMLDialogElement;
 | |
| 
 | |
| 	async function getApplicationList() {
 | |
| 		applications = await post('application/list', {});
 | |
| 	}
 | |
| 
 | |
| 	function docKey(e: KeyboardEvent) {
 | |
| 		if (e.ctrlKey && e.code === 'KeyK') {
 | |
| 			applications = [];
 | |
| 			getApplicationList();
 | |
| 			dialogElement.showModal();
 | |
| 			e.stopPropagation();
 | |
| 			e.preventDefault();
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	$effect(() => {
 | |
| 		document.addEventListener('keydown', docKey, false);
 | |
| 		return () => {
 | |
| 			document.removeEventListener('keydown', docKey);
 | |
| 		};
 | |
| 	});
 | |
| </script>
 | |
| 
 | |
| <dialog class="card max-w-[50vw]" bind:this={dialogElement}>
 | |
| 	<div class="flex">
 | |
| 		<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
 | |
| 		<div>
 | |
| 			{applications.length}
 | |
| 		</div>
 | |
| 	</div>
 | |
| 	<div class="overflow-y-auto overflow-x-hidden flex-grow p-2">
 | |
| 		<!-- TODO loading screen -->
 | |
| 		{#each applications.filter((i) => {
 | |
| 			if (application && i.id == application.id) {
 | |
| 				return false;
 | |
| 			}
 | |
| 			if (!filter) {
 | |
| 				return true;
 | |
| 			}
 | |
| 
 | |
| 			if (filter.includes('@') && i.company) {
 | |
| 				const splits = filter.split('@');
 | |
| 				const f = new RegExp(splits[0].trim(), 'ig');
 | |
| 				const c = new RegExp(splits[1].trim(), 'ig');
 | |
| 				return i.title.match(f) && i.company.match(c);
 | |
| 			}
 | |
| 
 | |
| 			const f = new RegExp(filter, 'ig');
 | |
| 
 | |
| 			let x = i.title;
 | |
| 
 | |
| 			if (i.company) {
 | |
| 				x = `${x} @ ${i.company}`;
 | |
| 			}
 | |
| 
 | |
| 			return x.match(f);
 | |
| 		}) as item}
 | |
| 			<div class="card p-2 my-2 bg-slate-100 max-w-full" role="none">
 | |
| 				<button
 | |
| 					class="text-left max-w-full"
 | |
| 					type="button"
 | |
| 					onclick={() => {
 | |
| 						dialogElement.close();
 | |
| 						onreload(item);
 | |
| 					}}
 | |
| 				>
 | |
| 					<h2 class="text-lg text-blue-500 flex justify-between">
 | |
| 						<div>
 | |
| 							{item.title}
 | |
| 							{#if item.company}
 | |
| 								<div class="text-violet-800">
 | |
| 									@ {item.company}
 | |
| 								</div>
 | |
| 							{/if}
 | |
| 						</div>
 | |
| 						<div>
 | |
| 							{ApplicationStatusMaping[item.status]}
 | |
| 						</div>
 | |
| 					</h2>
 | |
| 					<span
 | |
| 						class="text-violet-600 overflow-hidden whitespace-nowrap block max-w-full"
 | |
| 					>
 | |
| 						{item.url}
 | |
| 					</span>
 | |
| 				</button>
 | |
| 			</div>
 | |
| 		{/each}
 | |
| 	</div>
 | |
| </dialog>
 |