feature: engine change & nextui

This commit is contained in:
Alikia2x 2024-04-04 02:26:37 +08:00
parent 090154115a
commit 09a7941eca
15 changed files with 2870 additions and 311 deletions

1
.npmrc Normal file
View File

@ -0,0 +1 @@
public-hoist-pattern[]=*@nextui-org/*

View File

@ -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
View 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>
)
}

View File

@ -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)} />
)}

View 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>
);
}

View File

@ -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";

View File

@ -0,0 +1 @@
export const engineTranslation = ["google", "bing", "baidu", "duckduckgo", "yandex", "ecosia", "yahoo"];

View File

@ -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 };

View 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;
}
}

View File

@ -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){

View File

@ -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"
}
}

View File

@ -1,6 +1,16 @@
{
"Search": {
"placeholder": "搜索或输入网址"
"placeholder": "搜索或输入网址",
"engine-aria": "搜索引擎切换",
"engine": {
"google": "谷歌",
"baidu": "百度",
"bing": "必应",
"duckduckgo": "DuckDuckGo",
"yandex": "Yandex",
"yahoo": "雅虎",
"ecosia": "Ecosia"
}
},
"404": {
"title": "未找到"

View File

@ -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",

File diff suppressed because it is too large Load Diff

View File

@ -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;