ref: use react router
fix: a critical performance issue add: inpage-link for onesearch
This commit is contained in:
parent
263b82c06e
commit
609f1abe31
@ -1,30 +1,30 @@
|
||||
import { normalizeURL } from "lib/normalizeURL";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
export default function Link(props: { children: React.ReactNode; query: string; selected: boolean }) {
|
||||
if (props.selected) {
|
||||
return (
|
||||
<div
|
||||
className={`w-full h-10 leading-10 bg-zinc-300 dark:bg-zinc-700
|
||||
px-5 z-10 cursor-pointer duration-100`}
|
||||
onClick={() => {
|
||||
window.open(normalizeURL(props.query));
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<div
|
||||
className={`w-full h-10 leading-10 bg-zinc-100 hover:bg-zinc-300
|
||||
dark:bg-zinc-800 hover:dark:bg-zinc-700 px-5 z-10 cursor-pointer duration-100`}
|
||||
onClick={() => {
|
||||
window.open(normalizeURL(props.query));
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
interface LinkSuggestionProps {
|
||||
children: React.ReactNode;
|
||||
query: string;
|
||||
selected: boolean;
|
||||
inPage?: boolean;
|
||||
}
|
||||
|
||||
export default function LinkSuggestion(props: LinkSuggestionProps) {
|
||||
const className = props.selected
|
||||
? `w-full h-10 leading-10 bg-zinc-300 dark:bg-zinc-700 px-5 z-10 cursor-pointer duration-100`
|
||||
: `w-full h-10 leading-10 bg-zinc-100 hover:bg-zinc-300 dark:bg-zinc-800 hover:dark:bg-zinc-700 px-5 z-10 cursor-pointer duration-100`;
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onClick={() => {
|
||||
if (props.inPage) {
|
||||
navigate(props.query);
|
||||
} else {
|
||||
window.open(normalizeURL(props.query));
|
||||
}
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import getSearchEngineName from "lib/onesearch/getSearchEngineName";
|
||||
import PlainSearch from "./plainSearch";
|
||||
import { suggestionAtom } from "lib/state/suggestion";
|
||||
import validLink from "lib/url/validLink";
|
||||
import Link from "./link";
|
||||
import LinkSuggestion from "./link";
|
||||
import { selectedSuggestionAtom } from "lib/state/suggestionSelection";
|
||||
import { settingsAtom } from "lib/state/settings";
|
||||
import PlainText from "./plainText";
|
||||
@ -86,12 +86,14 @@ export default function OneSearch() {
|
||||
});
|
||||
}
|
||||
|
||||
(async function () {
|
||||
const NLU = await import("lib/nlp/load");
|
||||
const mainNLUModel = new NLU.NLU();
|
||||
setNLUModel(mainNLUModel);
|
||||
setNLUModelLoaded(true);
|
||||
})();
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
const NLU = await import("lib/nlp/load");
|
||||
const mainNLUModel = new NLU.NLU();
|
||||
setNLUModel(mainNLUModel);
|
||||
setNLUModelLoaded(true);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (NLUModel === null || NLUModel === undefined) {
|
||||
@ -172,7 +174,7 @@ export default function OneSearch() {
|
||||
s.type === "link"
|
||||
) {
|
||||
return (
|
||||
<Link key={i} query={s.suggestion} selected={i == selected}>
|
||||
<LinkSuggestion key={i} query={s.suggestion} selected={i == selected}>
|
||||
{s.prompt && (
|
||||
<span className="text-zinc-700 dark:text-zinc-400">{s.prompt}</span>
|
||||
)}
|
||||
@ -182,7 +184,7 @@ export default function OneSearch() {
|
||||
{s.relevance}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</LinkSuggestion>
|
||||
);
|
||||
} else if (s.type === "text") {
|
||||
return (
|
||||
@ -198,6 +200,25 @@ export default function OneSearch() {
|
||||
)}
|
||||
</PlainText>
|
||||
);
|
||||
} else if (s.type === "inpage-link") {
|
||||
return (
|
||||
<LinkSuggestion
|
||||
key={i}
|
||||
query={s.suggestion}
|
||||
selected={i == selected}
|
||||
inPage={true}
|
||||
>
|
||||
{s.prompt && (
|
||||
<span className="text-zinc-700 dark:text-zinc-400">{s.prompt}</span>
|
||||
)}
|
||||
{s.suggestion}
|
||||
{devMode && (
|
||||
<span className="absolute text-zinc-700 dark:text-zinc-400 text-sm leading-10 h-10 right-2">
|
||||
{s.relevance}
|
||||
</span>
|
||||
)}
|
||||
</LinkSuggestion>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</SuggestionBox>
|
||||
|
@ -18,8 +18,11 @@ export default function (
|
||||
} else if (selected.type === "NAVIGATION" || selected.type === "default-link") {
|
||||
window.open(normalizeURL(selected.suggestion));
|
||||
} else if (selected.type === "text") {
|
||||
console.log("????");
|
||||
copyToClipboard(selected.suggestion);
|
||||
searchBoxRef.current?.focus();
|
||||
} else if (selected.type === "link") {
|
||||
window.open(normalizeURL(selected.suggestion));
|
||||
} else if (selected.type === "inpage-link") {
|
||||
location.href = normalizeURL(selected.suggestion);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export function keywordSuggestion(query: string) {
|
||||
for (const keyword in dict_cn) {
|
||||
if (query.includes(keyword)) {
|
||||
const result: suggestionItem = {
|
||||
type: "link",
|
||||
type: "inpage-link",
|
||||
suggestion: dict_cn[keyword],
|
||||
prompt: keyword,
|
||||
relevance: 3000
|
||||
@ -27,7 +27,7 @@ export function keywordSuggestion(query: string) {
|
||||
for (const keyword in dict_en) {
|
||||
if (query.includes(keyword)) {
|
||||
const result: suggestionItem = {
|
||||
type: "link",
|
||||
type: "inpage-link",
|
||||
suggestion: dict_en[keyword],
|
||||
prompt: keyword,
|
||||
relevance: 3000
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sparkhome",
|
||||
"private": false,
|
||||
"version": "5.6.0",
|
||||
"version": "5.7.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun server.ts",
|
||||
|
@ -58,7 +58,7 @@ function Version(props: { title: string; version: string; versionClass?: string
|
||||
<span
|
||||
className={
|
||||
"relative px-2 py-1 text-sm font-bold rounded-md text-nowrap text-white " +
|
||||
props.versionClass ?? ""
|
||||
props.versionClass || ""
|
||||
}
|
||||
>
|
||||
{props.version}
|
||||
|
@ -12,8 +12,9 @@ export default function Homepage() {
|
||||
const setBgFocus = useSetAtom(bgFocusAtom);
|
||||
|
||||
return (
|
||||
<div className="h-screen fixed overflow-hidden w-screen bg-black">
|
||||
<div className="h-screen w-screen overflow-x-hidden bg-white dark:bg-[rgb(23,25,29)]">
|
||||
<Background />
|
||||
|
||||
<EngineSelector
|
||||
className="absolute top-20 lg:top-44 short:top-0 translate-x-[-50%] translate-y-[-0.2rem]
|
||||
left-1/2 w-11/12 sm:w-[700px] text:black text-right
|
||||
|
95
src/app.tsx
95
src/app.tsx
@ -1,74 +1,31 @@
|
||||
import { Suspense } from "react";
|
||||
import { useRoutes } from "react-router-dom";
|
||||
import routes from "~react-pages";
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import ICU from 'i18next-icu';
|
||||
import * as en from "i18n/en.json"
|
||||
import * as zh from "i18n/zh.json"
|
||||
import * as ja from "i18n/ja.json"
|
||||
import * as ar from "i18n/ar.json"
|
||||
import * as de from "i18n/de.json"
|
||||
import * as es from "i18n/es.json"
|
||||
import * as fr from "i18n/fr.json"
|
||||
import * as it from "i18n/it.json"
|
||||
import * as ko from "i18n/ko.json"
|
||||
import * as pt from "i18n/pt.json"
|
||||
import * as ru from "i18n/ru.json"
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
|
||||
i18n.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.use(LanguageDetector)
|
||||
.use(ICU)
|
||||
.init({
|
||||
resources: {
|
||||
en: {
|
||||
translation: en
|
||||
},
|
||||
zh: {
|
||||
translation: zh
|
||||
},
|
||||
ja: {
|
||||
translation: ja
|
||||
},
|
||||
ar: {
|
||||
translation: ar
|
||||
},
|
||||
de: {
|
||||
translation: de
|
||||
},
|
||||
es: {
|
||||
translation: es
|
||||
},
|
||||
fr: {
|
||||
translation: fr
|
||||
},
|
||||
it: {
|
||||
translation: it
|
||||
},
|
||||
ko: {
|
||||
translation: ko
|
||||
},
|
||||
pt: {
|
||||
translation: pt
|
||||
},
|
||||
ru: {
|
||||
translation: ru
|
||||
import "./i18n";
|
||||
import Homepage from "pages";
|
||||
import AboutPage from "pages/about";
|
||||
import LicensePage from "pages/about/license";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <Homepage />
|
||||
},
|
||||
{
|
||||
path: "about",
|
||||
element: <AboutPage />,
|
||||
children: [
|
||||
{
|
||||
path: "license",
|
||||
element: <LicensePage />
|
||||
}
|
||||
},
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
|
||||
},
|
||||
|
||||
detection: {
|
||||
order: ['navigator'],
|
||||
caches: []
|
||||
}
|
||||
});
|
||||
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
export function App() {
|
||||
return <Suspense fallback={<p>Loading...</p>}>{useRoutes(routes)}</Suspense>;
|
||||
return (
|
||||
<div className="relative bg-white dark:bg-black dark:text-white min-h-screen w-screen">
|
||||
<RouterProvider router={router} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
65
src/i18n.ts
Normal file
65
src/i18n.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import * as en from "i18n/en.json"
|
||||
import * as zh from "i18n/zh.json"
|
||||
import * as ja from "i18n/ja.json"
|
||||
import * as ar from "i18n/ar.json"
|
||||
import * as de from "i18n/de.json"
|
||||
import * as es from "i18n/es.json"
|
||||
import * as fr from "i18n/fr.json"
|
||||
import * as it from "i18n/it.json"
|
||||
import * as ko from "i18n/ko.json"
|
||||
import * as pt from "i18n/pt.json"
|
||||
import * as ru from "i18n/ru.json"
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import ICU from 'i18next-icu';
|
||||
i18n.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.use(LanguageDetector)
|
||||
.use(ICU)
|
||||
.init({
|
||||
resources: {
|
||||
en: {
|
||||
translation: en
|
||||
},
|
||||
zh: {
|
||||
translation: zh
|
||||
},
|
||||
ja: {
|
||||
translation: ja
|
||||
},
|
||||
ar: {
|
||||
translation: ar
|
||||
},
|
||||
de: {
|
||||
translation: de
|
||||
},
|
||||
es: {
|
||||
translation: es
|
||||
},
|
||||
fr: {
|
||||
translation: fr
|
||||
},
|
||||
it: {
|
||||
translation: it
|
||||
},
|
||||
ko: {
|
||||
translation: ko
|
||||
},
|
||||
pt: {
|
||||
translation: pt
|
||||
},
|
||||
ru: {
|
||||
translation: ru
|
||||
}
|
||||
},
|
||||
fallbackLng: "en",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
|
||||
},
|
||||
|
||||
detection: {
|
||||
order: ['navigator'],
|
||||
caches: []
|
||||
}
|
||||
});
|
@ -1,6 +1,5 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { App } from "./app";
|
||||
import "./index.css";
|
||||
import { NextUIProvider } from "@nextui-org/react";
|
||||
@ -9,10 +8,8 @@ const app = createRoot(document.getElementById("root")!);
|
||||
|
||||
app.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<NextUIProvider>
|
||||
<App />
|
||||
</NextUIProvider>
|
||||
</BrowserRouter>
|
||||
<NextUIProvider>
|
||||
<App />
|
||||
</NextUIProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
@ -7,6 +7,7 @@ const config: Config = {
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./node_modules/@nextui-org/theme/**/*.{js,ts,jsx,tsx}",
|
||||
"./src/**/*.{js,ts,jsx,tsx,mdx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import Pages from "vite-plugin-pages";
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { chunkSplitPlugin } from 'vite-plugin-chunk-split';
|
||||
|
||||
@ -8,9 +7,6 @@ import { chunkSplitPlugin } from 'vite-plugin-chunk-split';
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
Pages({
|
||||
dirs: "./pages/"
|
||||
}),
|
||||
tsconfigPaths(),
|
||||
chunkSplitPlugin()
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user