mirror of
https://github.com/anotherhadi/default-creds.git
synced 2026-04-02 11:32:11 +02:00
171 lines
4.7 KiB
Svelte
171 lines
4.7 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from "svelte";
|
|
import Result from "./Result.svelte";
|
|
import type { Result as ResultType } from "src/types/nav";
|
|
import { Search } from "lucide-svelte";
|
|
import DefaultView from "./DefaultView.svelte";
|
|
import NotFoundView from "./NotFoundView.svelte";
|
|
import { cleanUserInput } from "@lib/utils";
|
|
|
|
let queryInput = $state("");
|
|
let lastQuery = $state("");
|
|
let results = $state<ResultType[]>([]);
|
|
let loading = $state(false);
|
|
|
|
let currentPage = $state(1);
|
|
let totalPages = $state(1);
|
|
const defaultPageSize = 10;
|
|
let pageSize = $state(10);
|
|
let totalResults = $state(0);
|
|
|
|
onMount(() => {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const q = params.get("q");
|
|
const p = params.get("page");
|
|
const s = params.get("size");
|
|
|
|
if (q) {
|
|
queryInput = q;
|
|
if (p) currentPage = parseInt(p);
|
|
if (s) pageSize = parseInt(s);
|
|
search(currentPage, false);
|
|
}
|
|
});
|
|
|
|
async function search(page = 1, updateUrl = true) {
|
|
if (!queryInput.trim()) {
|
|
results = [];
|
|
lastQuery = "";
|
|
currentPage = 1;
|
|
|
|
if (updateUrl) {
|
|
window.history.pushState({}, "", window.location.pathname);
|
|
}
|
|
return;
|
|
}
|
|
|
|
loading = true;
|
|
lastQuery = queryInput;
|
|
currentPage = page;
|
|
|
|
try {
|
|
const params = new URLSearchParams({
|
|
q: lastQuery,
|
|
page: currentPage.toString(),
|
|
size: pageSize.toString(),
|
|
});
|
|
|
|
if (updateUrl) {
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.set("q", lastQuery);
|
|
|
|
if (currentPage > 1)
|
|
url.searchParams.set("page", currentPage.toString());
|
|
else url.searchParams.delete("page");
|
|
|
|
if (pageSize !== defaultPageSize)
|
|
url.searchParams.set("size", pageSize.toString());
|
|
else url.searchParams.delete("size");
|
|
|
|
window.history.pushState({}, "", url);
|
|
}
|
|
|
|
const res = await fetch(`/api/search?${params.toString()}`);
|
|
const data = await res.json();
|
|
results = data.results;
|
|
totalPages = data.pagination.totalPages;
|
|
totalResults = data.pagination.totalResults;
|
|
if (typeof window !== "undefined" && (window as any).umami) {
|
|
(window as any).umami.track("search", {
|
|
query: lastQuery,
|
|
results: totalResults,
|
|
hasResults: totalResults > 0,
|
|
});
|
|
if (totalResults === 0) {
|
|
(window as any).umami.track("search_no_results", {
|
|
query: lastQuery,
|
|
});
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error("Search error:", e);
|
|
results = [];
|
|
} finally {
|
|
loading = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="flex flex-col items-center w-full">
|
|
<div class="form-control w-full mb-10">
|
|
<div class="join w-full">
|
|
<div class="w-full">
|
|
<label
|
|
class="input border-none bg-base-200 join-item w-full flex items-center gap-2"
|
|
>
|
|
<Search class="opacity-50" size={14} />
|
|
<input
|
|
type="text"
|
|
placeholder="Search password for..."
|
|
bind:value={queryInput}
|
|
onkeydown={(e) => e.key === "Enter" && search(1)}
|
|
required
|
|
/>
|
|
</label>
|
|
</div>
|
|
<button
|
|
class="btn btn-soft border join-item"
|
|
disabled={loading}
|
|
onclick={() => search(1)}
|
|
>
|
|
Search
|
|
{#if loading}
|
|
<span class="loading loading-spinner"></span>
|
|
{/if}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 gap-6 w-full">
|
|
{#if loading}
|
|
<div class="col-span-full flex justify-center py-10">
|
|
<span class="loading loading-dots loading-lg"></span>
|
|
</div>
|
|
{:else if lastQuery === ""}
|
|
<DefaultView />
|
|
{:else if results.length > 0}
|
|
<ul class="list rounded-box">
|
|
<li class="px-4 pb-2 text-xs opacity-60 tracking-wide">
|
|
{totalResults} result{(totalResults > 1 && "s") || ""} for the query '{cleanUserInput(
|
|
lastQuery,
|
|
)}'
|
|
</li>
|
|
|
|
{#each results as result}
|
|
<Result {result} />
|
|
{/each}
|
|
</ul>
|
|
|
|
{#if totalPages > 1}
|
|
<div class="join self-center mt-8 m-auto">
|
|
<button
|
|
class="join-item btn btn-md"
|
|
disabled={currentPage === 1}
|
|
onclick={() => search(currentPage - 1)}>«</button
|
|
>
|
|
<button class="join-item btn btn-md no-animation"
|
|
>Page {currentPage} / {totalPages}</button
|
|
>
|
|
<button
|
|
class="join-item btn btn-md"
|
|
disabled={currentPage === totalPages}
|
|
onclick={() => search(currentPage + 1)}>»</button
|
|
>
|
|
</div>
|
|
{/if}
|
|
{:else}
|
|
<NotFoundView {lastQuery} />
|
|
{/if}
|
|
</div>
|
|
</div>
|