Skip to content

Commit

Permalink
feat: update quick search
Browse files Browse the repository at this point in the history
  • Loading branch information
velut committed Jul 5, 2024
1 parent cc241cc commit 839aaab
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 41 deletions.
1 change: 1 addition & 0 deletions lib/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const mod = (a: number, b: number): number => ((a % b) + b) % b;
31 changes: 28 additions & 3 deletions src/components/QuickSearch.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,45 @@
---

<dialog
x-data
x-data="quickSearch()"
id="quick-search"
class="open:modal open:modal-bottom open:md:modal-middle"
@close="$store.quickSearch.close()"
@close="close()"
open
>
<div class="modal-box">
{/* Close button. */}
<form method="dialog">
<button class="btn btn-circle btn-ghost btn-sm absolute right-2 top-2">✕</button>
</form>

{/* Title. */}
<h3 class="text-lg font-bold">Quick search</h3>
<p class="py-4">Press ESC key or click outside to close</p>

{/* Search input. */}
<label for="quick-search-input" class="sr-only">Search for symbols in this package</label>
<input
autofocus
id="quick-search-input"
type="search"
class="input input-bordered w-full"
x-model="query"
@keydown.up.prevent="prevResult()"
@keydown.down.prevent="nextResult()"
@keydown.enter.prevent="useResult()"
/>

{/* Search results. */}
<ul class="mt-4 h-64 overflow-hidden overflow-y-auto" x-ref="quickSearchResults">
<template x-for="(result, i) in results">
<li :class="{ 'bg-red-400': i === cursor }">
<a href="" x-text="result"></a>
</li>
</template>
</ul>
</div>

{/* Clickable backdrop to close modal. */}
<form method="dialog" class="modal-backdrop">
<button>Close quick search</button>
</form>
Expand Down
6 changes: 3 additions & 3 deletions src/components/QuickSearchButton.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import LucideFileSearch from "~icons/lucide/file-search";
---

<button
x-data
x-data="quickSearchOpener()"
class="btn btn-outline w-full justify-between border-base-content/50"
@click="$store.quickSearch.open()"
@keydown.ctrl.k.window.prevent="$store.quickSearch.open()"
@click="open()"
@keydown.ctrl.k.window.prevent="open()"
>
<div class="flex items-center gap-2">
<LucideFileSearch class="size-6" />
Expand Down
126 changes: 91 additions & 35 deletions src/scripts/alpine.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import type { Alpine } from "alpinejs";
import { formatDistanceStrict } from "date-fns";

type QuickSearchStore = {
dialog: HTMLDialogElement | undefined;
isOpen: boolean;
query: string;
init(): void;
open(): void;
close(): void;
};
import { mod } from "../../lib/mod";

export default (Alpine: Alpine) => {
timeAgo(Alpine);
quickSearchStore(Alpine);
quickSearchOpener(Alpine);
quickSearch(Alpine);
};

const timeAgo = (Alpine: Alpine) => {
Expand All @@ -21,29 +14,92 @@ const timeAgo = (Alpine: Alpine) => {
}));
};

const quickSearchStore = (Alpine: Alpine) => {
Alpine.store("quickSearch", {
dialog: undefined,
isOpen: false,
query: "",
init() {
this.dialog = (document.querySelector("#quick-search") ?? undefined) as any;
console.log("init");
},
open() {
if (this.dialog && !this.dialog.open) {
this.isOpen = true;
this.dialog.showModal();
console.log("open");
}
},
close() {
if (this.dialog) {
this.dialog.close();
this.query = "";
this.isOpen = false;
console.log("close");
}
},
} as QuickSearchStore);
type QuickSearchOpener = {
dialog: HTMLDialogElement | undefined;
init(): void;
open(): void;
};

const quickSearchOpener = (Alpine: Alpine) => {
Alpine.data(
"quickSearchOpener",
() =>
({
dialog: undefined,
init() {
this.dialog = (document.querySelector("#quick-search") ?? undefined) as any;
},
open() {
if (this.dialog && !this.dialog.open) {
this.dialog.showModal();
}
},
}) as QuickSearchOpener,
);
};

type QuickSearch = {
$refs: {
quickSearchResults: HTMLUListElement;
};
$watch(target: string, callback: () => void): void;
dialog: HTMLDialogElement | undefined;
query: string;
declarations: number[];
cursor: number;
results: number[];
init(): void;
close(): void;
prevResult(): void;
nextResult(): void;
useResult(): void;
focusResult(): void;
};

const quickSearch = (Alpine: Alpine) => {
Alpine.data(
"quickSearch",
() =>
({
dialog: undefined,
query: "",
declarations: Array.from({ length: 100 }, (_, i) => i + 1),
cursor: 0,
get results() {
if (!this.query) {
return this.declarations;
}
return this.declarations.filter((declaration) => declaration > Number(this.query));
},
init() {
this.dialog = (document.querySelector("#quick-search") ?? undefined) as any;
this.$watch("query", () => {
this.cursor = 0;
});
this.$watch("cursor", () => {
this.focusResult();
});
},
close() {
if (this.dialog) {
this.dialog.close();
this.query = "";
}
},
prevResult() {
this.cursor = mod(this.cursor - 1, this.results.length);
},
nextResult() {
this.cursor = mod(this.cursor + 1, this.results.length);
},
useResult() {
console.log("useResult");
},
focusResult() {
this.$refs.quickSearchResults.children[this.cursor + 1]?.scrollIntoView({
block: "nearest",
});
},
}) as QuickSearch,
);
};

0 comments on commit 839aaab

Please sign in to comment.