feature: engine change & nextui
This commit is contained in:
parent
090154115a
commit
09a7941eca
@ -2,6 +2,8 @@ import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import "./global.css";
|
||||
import { NextIntlClientProvider, useMessages } from "next-intl";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { Providers } from "../providers";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
@ -22,11 +24,15 @@ export default function LocaleLayout({
|
||||
}) {
|
||||
const messages = useMessages();
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<body className={inter.className}>
|
||||
<ThemeProvider>
|
||||
<Providers>
|
||||
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
</Providers>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
12
app/providers.tsx
Normal file
12
app/providers.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
// app/providers.tsx
|
||||
'use client'
|
||||
|
||||
import {NextUIProvider} from '@nextui-org/react'
|
||||
|
||||
export function Providers({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<NextUIProvider>
|
||||
{children}
|
||||
</NextUIProvider>
|
||||
)
|
||||
}
|
@ -8,6 +8,7 @@ import Search from "./search/search";
|
||||
import { bgFocusState } from "./state/background";
|
||||
import Time from "./time";
|
||||
import loadSettings from "@/lib/loadSettings";
|
||||
import EngineSelector from "./search/engineSelector";
|
||||
|
||||
export default function Homepage() {
|
||||
const [settings, setSettings] = useRecoilState(settingsState);
|
||||
@ -36,6 +37,7 @@ export default function Homepage() {
|
||||
return (
|
||||
<div className="h-full fixed overflow-hidden w-full bg-black">
|
||||
<Time showSecond={settings.timeShowSecond} />
|
||||
<EngineSelector/>
|
||||
{colorScheme === "dark" && (
|
||||
<Background src="rgb(23,25,29)" isFocus={isFocus} onClick={() => setFocus(false)} />
|
||||
)}
|
||||
|
74
components/search/engineSelector.tsx
Normal file
74
components/search/engineSelector.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
"use client";
|
||||
|
||||
import React, { SetStateAction, useEffect, useState } from "react";
|
||||
import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button } from "@nextui-org/react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { settingsState } from "../state/settings";
|
||||
import { engineTranslation } from "./translatedEngineList";
|
||||
|
||||
export default function () {
|
||||
const t = useTranslations("Search");
|
||||
const settings: settings = useRecoilValue(settingsState);
|
||||
const items = settings.searchEngines;
|
||||
const currentEngine: string = settings.currentSearchEngine;
|
||||
const displayEngine = getName(currentEngine);
|
||||
const [selectedKeys, setSelectedKeys] = useState(new Set([currentEngine]) as any);
|
||||
const selectedValue = React.useMemo(() => Array.from(selectedKeys).join(", "), [selectedKeys]);
|
||||
const setSettings = useSetRecoilState(settingsState);
|
||||
|
||||
function setEngine(engine: string) {
|
||||
setSettings((oldSettings) => {
|
||||
return {
|
||||
...oldSettings,
|
||||
currentSearchEngine: engine
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getName(engineKey: string) {
|
||||
return engineTranslation.includes(engineKey) ? t(`engine.${engineKey}`) : engineKey;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedValue !== currentEngine) {
|
||||
setEngine(selectedValue);
|
||||
}
|
||||
}, [selectedValue]);
|
||||
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
isClient &&
|
||||
(
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button variant="bordered" className="capitalize">
|
||||
{displayEngine}
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
aria-label={t("engine-aria")}
|
||||
variant="flat"
|
||||
disallowEmptySelection
|
||||
selectionMode="single"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
{Object.keys(items).map((item) => (
|
||||
<DropdownItem key={item} suppressHydrationWarning>
|
||||
{getName(item)}
|
||||
</DropdownItem>
|
||||
))}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { atom, useRecoilValue } from "recoil";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { settingsState } from "../state/settings";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
|
1
components/search/translatedEngineList.ts
Normal file
1
components/search/translatedEngineList.ts
Normal file
@ -0,0 +1 @@
|
||||
export const engineTranslation = ["google", "bing", "baidu", "duckduckgo", "yandex", "ecosia", "yahoo"];
|
@ -1,23 +1,43 @@
|
||||
import isLocalStorageAvailable from "@/lib/isLocalStorageAvailable";
|
||||
import { atom } from "recoil";
|
||||
|
||||
const settingsState = atom({
|
||||
key: "settings",
|
||||
default: {
|
||||
const defaultSettings: settings = {
|
||||
version: 1,
|
||||
elementBackdrop: true,
|
||||
bgBlur: true,
|
||||
timeShowSecond: false,
|
||||
currentSearchEngine: "google",
|
||||
searchEngines: {
|
||||
"google": "https://www.google.com/search?q=%s",
|
||||
"bing": "https://www.bing.com/search?q=%s",
|
||||
"baidu": "https://www.baidu.com/s?wd=%s",
|
||||
"duckduckgo": "https://duckduckgo.com/?q=%s",
|
||||
"yandex": "https://yandex.com/search/?text=%s",
|
||||
google: "https://www.google.com/search?q=%s",
|
||||
bing: "https://www.bing.com/search?q=%s",
|
||||
baidu: "https://www.baidu.com/s?wd=%s",
|
||||
duckduckgo: "https://duckduckgo.com/?q=%s",
|
||||
yandex: "https://yandex.com/search/?text=%s",
|
||||
yahoo: "https://search.yahoo.com/search?p=%s",
|
||||
ecosia: "https://www.ecosia.org/search?q=%s"
|
||||
}
|
||||
};
|
||||
|
||||
const localStorageEffect =
|
||||
(key: any) =>
|
||||
({ setSelf, onSet }: any) => {
|
||||
if (isLocalStorageAvailable()===false){
|
||||
return;
|
||||
}
|
||||
const savedValue = localStorage.getItem(key);
|
||||
if (savedValue != null) {
|
||||
setSelf(JSON.parse(savedValue));
|
||||
}
|
||||
|
||||
onSet((newValue: settings) => {
|
||||
localStorage.setItem(key, JSON.stringify(newValue));
|
||||
});
|
||||
};
|
||||
|
||||
const settingsState = atom({
|
||||
key: "settings",
|
||||
default: defaultSettings,
|
||||
effects_UNSTABLE: [localStorageEffect("settings")]
|
||||
});
|
||||
|
||||
export {
|
||||
settingsState,
|
||||
}
|
||||
export { settingsState };
|
||||
|
10
lib/isLocalStorageAvailable.ts
Normal file
10
lib/isLocalStorageAvailable.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export default function(){
|
||||
var test = 'test';
|
||||
try {
|
||||
localStorage.setItem(test, test);
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import isLocalStorageAvailable from "./isLocalStorageAvailable";
|
||||
|
||||
const defaultSettings = {
|
||||
version: 1,
|
||||
elementBackdrop: true,
|
||||
@ -14,16 +16,7 @@ const defaultSettings = {
|
||||
"yandex": "https://yandex.com/search/?text=%s",
|
||||
}
|
||||
}
|
||||
function isLocalStorageAvailable(){
|
||||
var test = 'test';
|
||||
try {
|
||||
localStorage.setItem(test, test);
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default function (setSettings: any) {
|
||||
if (isLocalStorageAvailable()===false){
|
||||
|
@ -1,8 +1,21 @@
|
||||
{
|
||||
"Search": {
|
||||
"placeholder": "Search or type a URL"
|
||||
"placeholder": "Search or type a URL",
|
||||
"engine-aria": "Switch search engine",
|
||||
"engine": {
|
||||
"google": "Google",
|
||||
"baidu": "Baidu",
|
||||
"bing": "Bing",
|
||||
"duckduckgo": "DuckDuckGo",
|
||||
"yandex": "Yandex",
|
||||
"yahoo": "Yahoo",
|
||||
"ecosia": "Ecosia"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "Page Not Found"
|
||||
},
|
||||
"About": {
|
||||
"title": "SparkHome"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,16 @@
|
||||
{
|
||||
"Search": {
|
||||
"placeholder": "搜索或输入网址"
|
||||
"placeholder": "搜索或输入网址",
|
||||
"engine-aria": "搜索引擎切换",
|
||||
"engine": {
|
||||
"google": "谷歌",
|
||||
"baidu": "百度",
|
||||
"bing": "必应",
|
||||
"duckduckgo": "DuckDuckGo",
|
||||
"yandex": "Yandex",
|
||||
"yahoo": "雅虎",
|
||||
"ecosia": "Ecosia"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"title": "未找到"
|
||||
|
@ -10,10 +10,12 @@
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/react": "^2.2.10",
|
||||
"clsx": "^2.1.0",
|
||||
"framer-motion": "^11.0.24",
|
||||
"next": "14.1.1",
|
||||
"next": "14.1.4",
|
||||
"next-intl": "^3.10.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"punycode": "^2.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
2934
pnpm-lock.yaml
2934
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,21 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
import {nextui} from "@nextui-org/react";
|
||||
|
||||
const config: Config = {
|
||||
content: [
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
||||
"gradient-conic":
|
||||
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
||||
"gradient-conic": "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
plugins: [nextui()]
|
||||
};
|
||||
export default config;
|
||||
|
Loading…
Reference in New Issue
Block a user