From 6960ec5b35ff55a10d7a639b59e3d03ac42b3076 Mon Sep 17 00:00:00 2001 From: alikia2x Date: Fri, 5 Jul 2024 16:08:30 +0800 Subject: [PATCH] temp: try to replace selector component in nextui --- .prettierrc | 2 +- components/engineSelector.tsx | 64 +++++++++++--------------- components/search.tsx | 6 +-- components/selector.tsx | 85 +++++++++++++++++++++++++++++++++++ components/selectorItem.tsx | 12 +++++ components/time.tsx | 2 +- i18n/en.json | 4 +- pages/index.tsx | 16 +++++-- src/app.tsx | 36 +++++++-------- src/main.tsx | 5 ++- tailwind.config.ts | 6 +-- 11 files changed, 164 insertions(+), 74 deletions(-) create mode 100644 components/selector.tsx create mode 100644 components/selectorItem.tsx diff --git a/.prettierrc b/.prettierrc index 2341845..255a135 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,6 +3,6 @@ "tabWidth": 4, "trailingComma": "none", "singleQuote": false, - "printWidth": 120, + "printWidth": 100, "endOfLine": "lf" } diff --git a/components/engineSelector.tsx b/components/engineSelector.tsx index 01c95df..b2c3464 100644 --- a/components/engineSelector.tsx +++ b/components/engineSelector.tsx @@ -6,10 +6,8 @@ import { engineTranslation } from "lib/onesearch/translatedEngineList"; import { settingsType } from "global"; import { useAtomValue, useSetAtom } from "jotai"; -export default function EngineSelector( - props: { className: string } -) { - const { t } = useTranslation("Search"); +export default function EngineSelector(props: { className: string }) { + const { t } = useTranslation(); const settings: settingsType = useAtomValue(settingsAtom); const items = settings.searchEngines; const currentEngine: string = settings.currentSearchEngine; @@ -19,10 +17,8 @@ export default function EngineSelector( const selectedValue = React.useMemo(() => Array.from(selectedKeys).join(", "), [selectedKeys]); const setSettings = useSetAtom(settingsAtom); - - function getName(engineKey: string) { - return engineTranslation.includes(engineKey) ? t(`engine.${engineKey}`) : engineKey; + return engineTranslation.includes(engineKey) ? t(`search.engine.${engineKey}`) : engineKey; } useEffect(() => { @@ -39,39 +35,29 @@ export default function EngineSelector( } }, [currentEngine, selectedValue, setSettings]); - const [isClient, setIsClient] = useState(false); - - useEffect(() => { - setIsClient(true); - }, []); - return (
- { - isClient && - ( - - - - - - {Object.keys(items).map((item) => ( - - {getName(item)} - - ))} - - - )} + + + + + + {Object.keys(items).map((item) => ( + + {getName(item)} + + ))} + +
); -} \ No newline at end of file +} diff --git a/components/search.tsx b/components/search.tsx index fc14012..0097ec7 100644 --- a/components/search.tsx +++ b/components/search.tsx @@ -7,7 +7,6 @@ import handleEnter from "lib/onesearch/handleEnter"; import { suggestionAtom } from "lib/state/suggestion"; import { useTranslation } from "react-i18next"; - export default function Search(props: { onFocus: () => void }) { const { t } = useTranslation(); const settings = useAtomValue(settingsAtom); @@ -40,12 +39,13 @@ export default function Search(props: { onFocus: () => void }) {
diff --git a/components/selector.tsx b/components/selector.tsx new file mode 100644 index 0000000..ddc7f5d --- /dev/null +++ b/components/selector.tsx @@ -0,0 +1,85 @@ +import { HTMLAttributes, ReactNode, RefObject, useEffect, useRef } from "react"; +import { selectedOnChange } from "./selectorItem"; +import { createPortal } from "react-dom"; + +export type selectionType = string | number | boolean; + +interface PickerPropsChildrenStyle extends HTMLAttributes { + selected: selectionType; + selectionOnChange: selectedOnChange; + displayContent: string; + children: ReactNode; +} + +interface PickerPropsParamStyle extends HTMLAttributes { + selected: selectionType; + selectionOnChange: selectedOnChange; + displayContent: string; + selectionItems: PickedItem; +} + +interface PickedItem { + [key: string]: selectionType; +} + +export default function Picker(props: PickerPropsChildrenStyle | PickerPropsParamStyle) { + const itemListRef: RefObject = useRef(null); + const buttonRef: RefObject = useRef(null); + + const updatePosition = () => { + if (itemListRef.current == null || buttonRef.current == null) { + return; + } + const buttonRect = buttonRef.current.getBoundingClientRect(); + const listWidth = itemListRef.current.getBoundingClientRect().width; + // Align to center + itemListRef.current.style.left = buttonRect.x + buttonRect.width / 2 - listWidth / 2 + "px"; + itemListRef.current.style.top = buttonRect.y + buttonRect.height + 16 + "px"; + }; + + useEffect(() => { + updatePosition(); + const handleResize = () => { + updatePosition(); + }; + + window.addEventListener('resize', handleResize); + + // Cleanup event listener on component unmount + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [itemListRef, buttonRef]); + + if ("selectionItems" in props) { + const { selectionItems, displayContent, selectionOnChange, ...rest } = props; + return ( +
+ + {createPortal( +
+ {Object.keys(selectionItems).map((key: string, index) => { + return
{selectionItems[key]}
; + })} +
, + document.body + )} +
+ ); + } else { + return ( +
+ + {createPortal(
{props.children}
, document.body)} +
+ ); + } +} diff --git a/components/selectorItem.tsx b/components/selectorItem.tsx new file mode 100644 index 0000000..94469fa --- /dev/null +++ b/components/selectorItem.tsx @@ -0,0 +1,12 @@ +import { ReactNode } from "react"; +import { selectionType } from "./selector"; + +export type selectedOnChange = (target: selectionType) => void; + +export default function SelectionItem(props: {key: selectionType, children: ReactNode, onChange: selectedOnChange}){ + return ( +
props.onChange(props.key)}> + {props.children} +
+ ) +} \ No newline at end of file diff --git a/components/time.tsx b/components/time.tsx index 32831c9..54ae03a 100644 --- a/components/time.tsx +++ b/components/time.tsx @@ -32,7 +32,7 @@ export default function Time(props: { return (
{formatTime()}{" "} diff --git a/i18n/en.json b/i18n/en.json index 35caf64..b91b234 100755 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,5 +1,5 @@ { - "Search": { + "search": { "placeholder": "Search or type a URL", "engine-aria": "Switch search engine", "engine": { @@ -16,7 +16,7 @@ "404": { "title": "Page Not Found" }, - "About": { + "about": { "title": "SparkHome" }, "tools": { diff --git a/pages/index.tsx b/pages/index.tsx index b57b625..9219879 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -6,6 +6,7 @@ import { settingsAtom } from "lib/state/settings"; import { bgFocusAtom } from "lib/state/background"; import EngineSelector from "components/engineSelector"; import OneSearch from "components/onesearch/onesearch"; +import Picker from "components/selector"; export default function Homepage() { const settings = useAtomValue(settingsAtom); @@ -14,12 +15,21 @@ export default function Homepage() { return (
- + setBgFocus(true)} />
); } diff --git a/src/app.tsx b/src/app.tsx index a432ff6..ce118cb 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -3,20 +3,19 @@ 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 { NextUIProvider } from "@nextui-org/react"; +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" i18n.use(initReactI18next) // passes i18n down to react-i18next .use(LanguageDetector) @@ -64,15 +63,12 @@ i18n.use(initReactI18next) // passes i18n down to react-i18next }, detection: { - order: ["navigator"], + order: ['navigator'], caches: [] } }); + export function App() { - return ( - - Loading...

}>{useRoutes(routes)}
-
- ); + return Loading...

}>{useRoutes(routes)}
; } diff --git a/src/main.tsx b/src/main.tsx index 30f54c0..e26a904 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,13 +3,16 @@ 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"; const app = createRoot(document.getElementById("root")!); app.render( - + + + ); diff --git a/tailwind.config.ts b/tailwind.config.ts index ca7c3e9..412e2f9 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -6,8 +6,7 @@ const config: Config = { content: [ "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", - "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}" + "./node_modules/@nextui-org/theme/**/*.{js,ts,jsx,tsx}", ], theme: { extend: { @@ -17,7 +16,6 @@ const config: Config = { } } }, - darkMode: "class", - plugins: [nextui()], + plugins: [nextui()] }; export default config;