From cbaf9e6034aa09911fca967b7af6cad11f154b3e Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Tue, 31 Dec 2024 13:17:56 +0200
Subject: feat: Introduce advanced search capabilities (#753)

* feat: Implement search filtering in the backend

* feat: Implement search language parser

* rename matcher name

* Add ability to interleve text

* More fixes

* be more tolerable to parsing errors

* Add a search query explainer widget

* Handle date parsing gracefully

* Fix the lockfile

* Encode query search param

* Fix table body error

* Fix error when writing quotes
---
 .../dashboard/search/QueryExplainerTooltip.tsx     | 98 ++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 apps/web/components/dashboard/search/QueryExplainerTooltip.tsx

(limited to 'apps/web/components/dashboard/search/QueryExplainerTooltip.tsx')

diff --git a/apps/web/components/dashboard/search/QueryExplainerTooltip.tsx b/apps/web/components/dashboard/search/QueryExplainerTooltip.tsx
new file mode 100644
index 00000000..191c9ff3
--- /dev/null
+++ b/apps/web/components/dashboard/search/QueryExplainerTooltip.tsx
@@ -0,0 +1,98 @@
+import InfoTooltip from "@/components/ui/info-tooltip";
+import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
+
+import { TextAndMatcher } from "@hoarder/shared/searchQueryParser";
+import { Matcher } from "@hoarder/shared/types/search";
+
+export default function QueryExplainerTooltip({
+  parsedSearchQuery,
+  className,
+}: {
+  parsedSearchQuery: TextAndMatcher & { result: string };
+  className?: string;
+}) {
+  if (parsedSearchQuery.result == "invalid") {
+    return null;
+  }
+
+  const MatcherComp = ({ matcher }: { matcher: Matcher }) => {
+    switch (matcher.type) {
+      case "tagName":
+        return (
+          <TableRow>
+            <TableCell>Tag Name</TableCell>
+            <TableCell>{matcher.tagName}</TableCell>
+          </TableRow>
+        );
+      case "listName":
+        return (
+          <TableRow>
+            <TableCell>List Name</TableCell>
+            <TableCell>{matcher.listName}</TableCell>
+          </TableRow>
+        );
+      case "dateAfter":
+        return (
+          <TableRow>
+            <TableCell>Created After</TableCell>
+            <TableCell>{matcher.dateAfter.toDateString()}</TableCell>
+          </TableRow>
+        );
+      case "dateBefore":
+        return (
+          <TableRow>
+            <TableCell>Created Before</TableCell>
+            <TableCell>{matcher.dateBefore.toDateString()}</TableCell>
+          </TableRow>
+        );
+      case "favourited":
+        return (
+          <TableRow>
+            <TableCell>Favourited</TableCell>
+            <TableCell>{matcher.favourited.toString()}</TableCell>
+          </TableRow>
+        );
+      case "archived":
+        return (
+          <TableRow>
+            <TableCell>Archived</TableCell>
+            <TableCell>{matcher.archived.toString()}</TableCell>
+          </TableRow>
+        );
+      case "and":
+      case "or":
+        return (
+          <TableRow>
+            <TableCell className="capitalize">{matcher.type}</TableCell>
+            <TableCell>
+              <Table>
+                <TableBody>
+                  {matcher.matchers.map((m, i) => (
+                    <MatcherComp key={i} matcher={m} />
+                  ))}
+                </TableBody>
+              </Table>
+            </TableCell>
+          </TableRow>
+        );
+    }
+  };
+
+  return (
+    <InfoTooltip className={className}>
+      <Table>
+        <TableBody>
+          {parsedSearchQuery.text && (
+            <TableRow>
+              <TableCell>Text</TableCell>
+              <TableCell>{parsedSearchQuery.text}</TableCell>
+            </TableRow>
+          )}
+          {parsedSearchQuery.matcher && (
+            <MatcherComp matcher={parsedSearchQuery.matcher} />
+          )}
+        </TableBody>
+      </Table>
+    </InfoTooltip>
+  );
+}
-- 
cgit v1.2.3-70-g09d2

