diff --git a/components/search/onesearch/handleEnter.ts b/components/search/onesearch/handleEnter.ts
new file mode 100644
index 0000000..fdb8ca0
--- /dev/null
+++ b/components/search/onesearch/handleEnter.ts
@@ -0,0 +1,14 @@
+import { settingsType, suggestionItem } from "@/global";
+import { normalizeURL } from "@/lib/normalizeURL";
+import search from "@/lib/search";
+
+export default function (index: number, suggestion: suggestionItem[], query: string, settings: settingsType) {
+ const selected = suggestion[index];
+ const engine = settings.searchEngines[settings.currentSearchEngine];
+ const newTab = settings.searchInNewTab;
+ if (selected.type === "QUERY" || selected.type === "default") {
+ search(selected.suggestion, engine, newTab);
+ } else if (selected.type === "NAVIGATION") {
+ window.open(normalizeURL(selected.suggestion));
+ }
+}
diff --git a/components/search/onesearch/link.tsx b/components/search/onesearch/link.tsx
new file mode 100644
index 0000000..6cbbaf8
--- /dev/null
+++ b/components/search/onesearch/link.tsx
@@ -0,0 +1,30 @@
+import { normalizeURL } from "@/lib/normalizeURL";
+
+export default function (props: { children: React.ReactNode; query: string; selected: boolean }) {
+ if (props.selected) {
+ return (
+
{
+ window.open(normalizeURL(props.query));
+ }}
+ >
+ {props.children}
+
+ );
+ }
+ else {
+ return (
+ {
+ window.open(normalizeURL(props.query));
+ }}
+ >
+ {props.children}
+
+ );
+ }
+}
diff --git a/components/search/onesearch/onesearch.tsx b/components/search/onesearch/onesearch.tsx
index 8a24671..ddafdda 100644
--- a/components/search/onesearch/onesearch.tsx
+++ b/components/search/onesearch/onesearch.tsx
@@ -1,114 +1,108 @@
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import SuggestionBox from "./suggestionBox";
-import { useRecoilValue } from "recoil";
+import { useRecoilState, useRecoilValue } from "recoil";
import { queryState } from "@/components/state/query";
import { useLocale, useTranslations } from "next-intl";
import { suggestionItem, suggestionsResponse } from "@/global";
import getSearchEngineName from "@/lib/getSearchEngineName";
import PlainSearch from "./plainSearch";
+import { suggestionsState } from "@/components/state/suggestion";
+import validLink from "@/lib/url/validLink";
+import Link from "./link";
+import { selectedSuggestionState } from "@/components/state/suggestionSelection";
+import { settingsState } from "@/components/state/settings";
+import { base64NLP } from "@/lib/onesearch/baseCheck";
+import PlainText from "./plainText";
export default function () {
- const [suggestion, setFinalSuggetsion] = useState([] as suggestionItem[]);
- const [selected, setSelected] = useState(0);
- const [lastUpdate, setLastUpdate] = useState(0);
- const [cloudLastUpdate, setCloudLastUpdate] = useState(0);
- const [clientLastUpdate, setClientLastUpdate] = useState(0);
+ const [suggestion, setFinalSuggetsion] = useRecoilState(suggestionsState);
+ const lastRequestTimeRef = useRef(0);
+ const selected = useRecoilValue(selectedSuggestionState);
+ const settings = useRecoilValue(settingsState);
const devMode = true;
const query = useRecoilValue(queryState);
const engineName = getSearchEngineName();
+ const engine = settings.currentSearchEngine;
const lang = useLocale();
const t = useTranslations("Search");
useEffect(() => {
const time = new Date().getTime().toString();
if (query.trim() === "") {
- cleanSuggestion("QUERY", new Date().getTime());
+ cleanSuggestion("QUERY", "NAVIGATION");
return;
}
- fetch(`/api/suggestion?q=${query}&l=${lang}&t=${time}`)
+ fetch(`/api/suggestion?q=${query}&l=${lang}&t=${time}&engine=${engine}`)
.then((res) => res.json())
.then((data: suggestionsResponse) => {
let suggestionToUpdate: suggestionItem[] = data.suggestions;
- if (data.verbatimRelevance) {
- suggestionToUpdate.push({
- type: "default",
- suggestion: query,
- relevance: data.verbatimRelevance
- });
+ if (data.time > lastRequestTimeRef.current){
+ cleanSuggestion("NAVIGATION", "QUERY");
+ lastRequestTimeRef.current = data.time;
+ updateSuggestion(suggestionToUpdate);
}
- updateSuggestion(suggestionToUpdate, "cloud", data.time);
+
});
}, [query]);
- function setSuggestion(data: suggestionItem[], source: "frontend" | "client" | "cloud", time?: number) {
- let finalSuggestion = data.sort((a, b) => b.relevance - a.relevance);
- finalSuggestion = finalSuggestion.filter(
- (item, index, self) => index === self.findIndex((t) => t.suggestion === item.suggestion)
- );
- setFinalSuggetsion(finalSuggestion);
- const requestUpdateTime = time || new Date().getTime();
- const overwriteLastUpdate = requestUpdateTime > lastUpdate;
- switch (source) {
- case "frontend":
- setLastUpdate(new Date().getTime());
- break;
- case "client":
- setClientLastUpdate(requestUpdateTime);
- if (overwriteLastUpdate) setLastUpdate(new Date().getTime());
- case "cloud":
- setCloudLastUpdate(requestUpdateTime);
- if (overwriteLastUpdate) setLastUpdate(new Date().getTime());
- break;
- default:
- break;
- }
- }
-
- function updateSuggestion(data: suggestionItem[], source: "frontend" | "client" | "cloud", time?: number) {
- let finalSuggestion = suggestion;
- const types: string[] = [];
- for (let sug of data) {
- if (!types.includes(sug.type)) types.push(sug.type);
- }
- for (let type of types) {
- finalSuggestion = finalSuggestion.filter((item) => {
- return item.type !== type;
+ function updateSuggestion(data: suggestionItem[]) {
+ setFinalSuggetsion((cur: suggestionItem[]) => {
+ const types: string[] = [];
+ for (let sug of data) {
+ if (!types.includes(sug.type)) types.push(sug.type);
+ }
+ for (let type of types) {
+ cur = cur.filter((item) => {
+ return item.type !== type;
+ });
+ }
+ return cur.concat(data).sort((a, b) => {
+ return b.relevance - a.relevance;
});
- }
- finalSuggestion = finalSuggestion.concat(data);
- setSuggestion(finalSuggestion, source, time);
+ });
}
- function cleanSuggestion(type: string, time?: number){
- let finalSuggestion = suggestion;
- console.log("1",finalSuggestion);
- finalSuggestion = finalSuggestion.filter((item) => {
- return item.type !== type;
+ function cleanSuggestion(...types: string[]) {
+ setFinalSuggetsion((suggestion: suggestionItem[]) => {
+ return suggestion.filter((item) => {
+ return !types.includes(item.type);
+ });
});
- console.log("2",finalSuggestion);
- setSuggestion(finalSuggestion, "frontend", time);
}
useEffect(() => {
- updateSuggestion(
- [
+ if (validLink(query)) {
+ cleanSuggestion("default-link","default","text")
+ updateSuggestion([
+ { type: "default-link", suggestion: query, relevance: 3000 },
+ { type: "default", suggestion: query, relevance: 1600 }
+ ]);
+ } else {
+ cleanSuggestion("default-link","default","text")
+ updateSuggestion([
{
type: "default",
suggestion: query,
relevance: 2000
}
- ],
- "frontend"
- );
+ ]);
+ }
+ console.log(new Date().getTime());
+ const b64 = base64NLP(query);
+ console.log(new Date().getTime());
+ if (b64.suggestion!==null){
+ cleanSuggestion("default-link","default","text")
+ updateSuggestion([b64 as suggestionItem]);
+ }
}, [query, engineName]);
return (
- {suggestion.map((s) => {
+ {suggestion.map((s, i) => {
if (s.suggestion.trim() === "") return;
if (s.type === "default") {
return (
-
+
{s.suggestion}
{t("search-help-text", { engine: engineName })}
@@ -122,7 +116,7 @@ export default function () {
);
} else if (s.type === "QUERY") {
return (
-
+
{s.suggestion}
{devMode && (
@@ -131,6 +125,32 @@ export default function () {
)}
);
+ } else if (s.type === "NAVIGATION" || s.type === "default-link") {
+ return (
+
+ {s.suggestion}
+ {devMode && (
+
+ Relevance: {s.relevance}
+
+ )}
+
+ );
+ } else if (s.type === "text") {
+ return (
+
+ {s.suggestion}
+ {devMode && (
+
+ Relevance: {s.relevance}
+
+ )}
+
+ )
}
})}
diff --git a/components/search/onesearch/plainSearch.tsx b/components/search/onesearch/plainSearch.tsx
index b545a43..c8deb7e 100644
--- a/components/search/onesearch/plainSearch.tsx
+++ b/components/search/onesearch/plainSearch.tsx
@@ -2,17 +2,34 @@ import search from "@/lib/search";
import { settingsState } from "@/components/state/settings";
import { useRecoilValue } from "recoil";
-export default function (props: { children: React.ReactNode, query: string }) {
+export default function (props: { children: React.ReactNode; query: string; selected: boolean }) {
const settings = useRecoilValue(settingsState);
const engine = settings.searchEngines[settings.currentSearchEngine];
const newTab = settings.searchInNewTab;
- return (
- {search(props.query, engine, newTab)}}
- >
- {props.children}
-
- );
+ if (props.selected) {
+ return (
+ {
+ search(props.query, engine, newTab);
+ }}
+ >
+ {props.children}
+
+ );
+ }
+ else {
+ return (
+ {
+ search(props.query, engine, newTab);
+ }}
+ >
+ {props.children}
+
+ );
+ }
}
diff --git a/components/search/search.tsx b/components/search/search.tsx
index 20064ff..8fac048 100644
--- a/components/search/search.tsx
+++ b/components/search/search.tsx
@@ -3,28 +3,35 @@
import { useRecoilState, useRecoilValue } from "recoil";
import { settingsState } from "../state/settings";
import { useTranslations } from "next-intl";
-import { normalizeURL } from "@/lib/normalizeURL";
-import validLink from "@/lib/url/validLink";
import { queryState } from "../state/query";
import { settingsType } from "@/global";
+import handleEnter from "./onesearch/handleEnter";
+import { selectedSuggestionState } from "../state/suggestionSelection";
+import { suggestionsState } from "../state/suggestion";
+import { KeyboardEvent } from "react";
export default function Search(props: { onFocus: () => void }) {
const settings: settingsType = useRecoilValue(settingsState);
const t = useTranslations("Search");
const [query, setQuery] = useRecoilState(queryState);
+ const [selectedSuggestion, setSelected] = useRecoilState(selectedSuggestionState);
+ const suggestions = useRecoilValue(suggestionsState);
let style = "default";
- function handleKeydown(e: any) {
- let URL = "";
- if (validLink(query)) {
- URL = normalizeURL(query);
- } else {
- URL = settings.searchEngines[settings.currentSearchEngine];
- URL = URL.replace("%s", query);
- }
+ function handleKeydown(e: KeyboardEvent) {
if (e.key == "Enter") {
- location.href = URL;
+ e.preventDefault();
+ handleEnter(selectedSuggestion, suggestions, query, settings);
+ return;
+ } else if (e.key == "ArrowUp") {
+ e.preventDefault();
+ const len = suggestions.length;
+ setSelected((selectedSuggestion - 1 + len) % len);
+ } else if (e.key == "ArrowDown") {
+ e.preventDefault();
+ const len = suggestions.length;
+ setSelected((selectedSuggestion + 1) % len);
}
}
diff --git a/components/state/suggestion.ts b/components/state/suggestion.ts
new file mode 100644
index 0000000..4dc83ef
--- /dev/null
+++ b/components/state/suggestion.ts
@@ -0,0 +1,11 @@
+import { suggestionItem } from "@/global";
+import { atom } from "recoil";
+
+const suggestionsState = atom({
+ key: "oneSearchSuggestions",
+ default: [] as suggestionItem[]
+});
+
+export {
+ suggestionsState,
+}
\ No newline at end of file
diff --git a/components/state/suggestionSelection.ts b/components/state/suggestionSelection.ts
new file mode 100644
index 0000000..4142142
--- /dev/null
+++ b/components/state/suggestionSelection.ts
@@ -0,0 +1,10 @@
+import { atom } from "recoil";
+
+const selectedSuggestionState = atom({
+ key: "selectedSuggestion",
+ default: 0
+});
+
+export {
+ selectedSuggestionState,
+}
\ No newline at end of file
diff --git a/lib/normalizeURL.ts b/lib/normalizeURL.ts
index 998b3b9..e6aa831 100644
--- a/lib/normalizeURL.ts
+++ b/lib/normalizeURL.ts
@@ -12,7 +12,6 @@ export function normalizeURL(input: string): string {
return urlWithHTTP.href;
} catch (error) {
// if the URL is still invalid, return the original input
- console.error("Invalid URL:", input);
return input;
}
}