ref: format
This commit is contained in:
parent
35f90b42d9
commit
d97e678206
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"useTabs": false,
|
"useTabs": true,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
|
@ -2,10 +2,10 @@ import { Express } from "express";
|
|||||||
import { completeGoogle } from "search-engine-autocomplete";
|
import { completeGoogle } from "search-engine-autocomplete";
|
||||||
|
|
||||||
export function configureBackendRoutes(app: Express) {
|
export function configureBackendRoutes(app: Express) {
|
||||||
app.get('/api/v1/suggestion', async (req, res) => {
|
app.get("/api/v1/suggestion", async (req, res) => {
|
||||||
const query = req.query.q as string;
|
const query = req.query.q as string;
|
||||||
const t = parseInt(req.query.t as string || "0") || null;
|
const t = parseInt((req.query.t as string) || "0") || null;
|
||||||
let language = req.query.l as string || 'en-US';
|
let language = (req.query.l as string) || "en-US";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await completeGoogle(query, language);
|
const data = await completeGoogle(query, language);
|
||||||
@ -13,10 +13,10 @@ export function configureBackendRoutes(app: Express) {
|
|||||||
res.json({ ...data, time: t });
|
res.json({ ...data, time: t });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
//logger.error({ type: "onesearch_search_autocomplete_error", error: error.message });
|
//logger.error({ type: "onesearch_search_autocomplete_error", error: error.message });
|
||||||
res.status(500).json({ error: 'Internal Server Error' });
|
res.status(500).json({ error: "Internal Server Error" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
app.get("/api/v1/ping", async (_, res) => {
|
app.get("/api/v1/ping", async (_, res) => {
|
||||||
res.status(200).json({ message: "pong" });
|
res.status(200).json({ message: "pong" });
|
||||||
})
|
});
|
||||||
}
|
}
|
@ -11,9 +11,19 @@ export default function Background() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{darkMode ? (
|
{darkMode ? (
|
||||||
<BackgroundContainer src="rgb(23,25,29)" isFocus={isFocus} onClick={() => setFocus(false)} darkMode={darkMode}/>
|
<BackgroundContainer
|
||||||
|
src="rgb(23,25,29)"
|
||||||
|
isFocus={isFocus}
|
||||||
|
onClick={() => setFocus(false)}
|
||||||
|
darkMode={darkMode}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<BackgroundContainer src="white" isFocus={isFocus} onClick={() => setFocus(false)} darkMode={darkMode}/>
|
<BackgroundContainer
|
||||||
|
src="white"
|
||||||
|
isFocus={isFocus}
|
||||||
|
onClick={() => setFocus(false)}
|
||||||
|
darkMode={darkMode}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -24,7 +24,11 @@ export default function BackgroundContainer(props: {
|
|||||||
src={props.src}
|
src={props.src}
|
||||||
className={
|
className={
|
||||||
"w-full h-full fixed object-cover inset-0 duration-200 z-0 " +
|
"w-full h-full fixed object-cover inset-0 duration-200 z-0 " +
|
||||||
(props.isFocus ? (settings.bgBlur ? "blur-lg scale-110" : "brightness-50 scale-105") : "")
|
(props.isFocus
|
||||||
|
? settings.bgBlur
|
||||||
|
? "blur-lg scale-110"
|
||||||
|
: "brightness-50 scale-105"
|
||||||
|
: "")
|
||||||
}
|
}
|
||||||
alt="background"
|
alt="background"
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
|
@ -13,9 +13,7 @@ export function handleNLUResult(result: any, updateSuggestion: UpdateSuggestionF
|
|||||||
if (data instanceof GeolocationCoordinates) {
|
if (data instanceof GeolocationCoordinates) {
|
||||||
getWeather(data.latitude, data.longitude).then((weather) => {
|
getWeather(data.latitude, data.longitude).then((weather) => {
|
||||||
console.log(weather["hourly"]);
|
console.log(weather["hourly"]);
|
||||||
let hourIndex = findClosestDateIndex(
|
let hourIndex = findClosestDateIndex(weather["hourly"]["time"]);
|
||||||
weather["hourly"]["time"]
|
|
||||||
);
|
|
||||||
let temp = weather["hourly"]["apparent_temperature"][hourIndex];
|
let temp = weather["hourly"]["apparent_temperature"][hourIndex];
|
||||||
let weatherCode = weather["hourly"]["weather_code"][hourIndex];
|
let weatherCode = weather["hourly"]["weather_code"][hourIndex];
|
||||||
console.log(temp, weatherCode, hourIndex);
|
console.log(temp, weatherCode, hourIndex);
|
||||||
|
@ -2,7 +2,11 @@ import { useAtomValue } from "jotai";
|
|||||||
import search from "lib/search";
|
import search from "lib/search";
|
||||||
import { settingsAtom } from "lib/state/settings";
|
import { settingsAtom } from "lib/state/settings";
|
||||||
|
|
||||||
export default function PlainSearch(props: { children: React.ReactNode; query: string; selected: boolean }) {
|
export default function PlainSearch(props: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
query: string;
|
||||||
|
selected: boolean;
|
||||||
|
}) {
|
||||||
const settings = useAtomValue(settingsAtom);
|
const settings = useAtomValue(settingsAtom);
|
||||||
const engine = settings.searchEngines[settings.currentSearchEngine];
|
const engine = settings.searchEngines[settings.currentSearchEngine];
|
||||||
const newTab = settings.searchInNewTab;
|
const newTab = settings.searchInNewTab;
|
||||||
@ -18,8 +22,7 @@ export default function PlainSearch(props: { children: React.ReactNode; query: s
|
|||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`relative w-full h-10 leading-10 bg-zinc-100 hover:bg-zinc-300
|
className={`relative w-full h-10 leading-10 bg-zinc-100 hover:bg-zinc-300
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
export default function Suggestion(props: { children: React.ReactNode }) {
|
export default function Suggestion(props: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div dangerouslySetInnerHTML={{ __html: `<p>${props.children}</p>` as string }} className={`relative 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`}>
|
<div
|
||||||
</div>
|
dangerouslySetInnerHTML={{ __html: `<p>${props.children}</p>` as string }}
|
||||||
|
className={`relative 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`}
|
||||||
|
></div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -142,7 +142,12 @@ const PickerList = React.forwardRef<HTMLDivElement, PickerListProps>((props, ref
|
|||||||
const { selected, selectionOnChange, selectionItems, toggleDisplay } = props;
|
const { selected, selectionOnChange, selectionItems, toggleDisplay } = props;
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<div className="absolute w-screen h-screen" onClick={()=>{toggleDisplay(false)}}>
|
<div
|
||||||
|
className="absolute w-screen h-screen"
|
||||||
|
onClick={() => {
|
||||||
|
toggleDisplay(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="overflow-y-auto fixed w-fit text-black dark:text-white opacity-0 duration-200
|
className="overflow-y-auto fixed w-fit text-black dark:text-white opacity-0 duration-200
|
||||||
|
@ -3,10 +3,10 @@ import { selectionType } from "./picker";
|
|||||||
|
|
||||||
export type selectedOnChange = (target: selectionType) => void;
|
export type selectedOnChange = (target: selectionType) => void;
|
||||||
|
|
||||||
export default function SelectionItem(props: {key: selectionType, children: ReactNode, onChange: selectedOnChange}){
|
export default function SelectionItem(props: {
|
||||||
return (
|
key: selectionType;
|
||||||
<div onClick={() => props.onChange(props.key)}>
|
children: ReactNode;
|
||||||
{props.children}
|
onChange: selectedOnChange;
|
||||||
</div>
|
}) {
|
||||||
)
|
return <div onClick={() => props.onChange(props.key)}>{props.children}</div>;
|
||||||
}
|
}
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
export default function Time(props: {
|
export default function Time(props: { showSecond: boolean }) {
|
||||||
showSecond: boolean
|
|
||||||
}) {
|
|
||||||
const [currentTime, setCurrentTime] = useState(new Date());
|
const [currentTime, setCurrentTime] = useState(new Date());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
44
global.d.ts
vendored
44
global.d.ts
vendored
@ -1,31 +1,31 @@
|
|||||||
import { Suggestion } from "search-engine-autocomplete";
|
import { Suggestion } from "search-engine-autocomplete";
|
||||||
|
|
||||||
interface settingsType extends object {
|
interface settingsType extends object {
|
||||||
"version": number,
|
version: number;
|
||||||
"elementBackdrop": boolean,
|
elementBackdrop: boolean;
|
||||||
"bgBlur": boolean,
|
bgBlur: boolean;
|
||||||
"timeShowSecond": boolean,
|
timeShowSecond: boolean;
|
||||||
"currentSearchEngine": string,
|
currentSearchEngine: string;
|
||||||
"searchInNewTab": boolean,
|
searchInNewTab: boolean;
|
||||||
"searchEngines": {
|
searchEngines: {
|
||||||
[key: string]: string
|
[key: string]: string;
|
||||||
},
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface suggestionsResponse extends object {
|
interface suggestionsResponse extends object {
|
||||||
suggestions: Suggestion[],
|
suggestions: Suggestion[];
|
||||||
query: string,
|
query: string;
|
||||||
verbatimRelevance: number,
|
verbatimRelevance: number;
|
||||||
time: number
|
time: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type suggestionItem = {
|
type suggestionItem = {
|
||||||
suggestion: string,
|
suggestion: string;
|
||||||
type: string,
|
type: string;
|
||||||
relativeRelevance?: number,
|
relativeRelevance?: number;
|
||||||
relevance: number,
|
relevance: number;
|
||||||
prompt?: string | React.ReactElement,
|
prompt?: string | React.ReactElement;
|
||||||
intention?: string | null,
|
intention?: string | null;
|
||||||
probability?: number,
|
probability?: number;
|
||||||
confidence?: number,
|
confidence?: number;
|
||||||
}
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
@ -137,11 +137,5 @@
|
|||||||
"Which framework do you think is the most suitable for performance sensitive projects?"
|
"Which framework do you think is the most suitable for performance sensitive projects?"
|
||||||
],
|
],
|
||||||
|
|
||||||
"None": [
|
"None": ["free weather api", "js get timezone", "how", "how's", "how's the"]
|
||||||
"free weather api",
|
|
||||||
"js get timezone",
|
|
||||||
"how",
|
|
||||||
"how's",
|
|
||||||
"how's the"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -117,11 +117,5 @@
|
|||||||
"HTML实体转文本:%s"
|
"HTML实体转文本:%s"
|
||||||
],
|
],
|
||||||
|
|
||||||
"None": [
|
"None": ["你好", "为什么计算机使用二进制", "什么是", "热", "怎么"]
|
||||||
"你好",
|
|
||||||
"为什么计算机使用二进制",
|
|
||||||
"什么是",
|
|
||||||
"热",
|
|
||||||
"怎么"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { NluManager, NluNeural } from "@nlpjs/nlu";
|
|||||||
import { LangEn } from "@nlpjs/lang-en-min";
|
import { LangEn } from "@nlpjs/lang-en-min";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { LangZh } from "@nlpjs/lang-zh";
|
import { LangZh } from "@nlpjs/lang-zh";
|
||||||
import * as fflate from 'fflate';
|
import * as fflate from "fflate";
|
||||||
|
|
||||||
export interface NLUType {
|
export interface NLUType {
|
||||||
manager: any;
|
manager: any;
|
||||||
@ -18,7 +18,6 @@ export interface NLUType {
|
|||||||
process(lang: string, text: string): Promise<any>;
|
process(lang: string, text: string): Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class NLU {
|
export class NLU {
|
||||||
manager: any;
|
manager: any;
|
||||||
inited: boolean = false;
|
inited: boolean = false;
|
||||||
|
@ -9,7 +9,7 @@ import { LangEn } from "@nlpjs/lang-en-min";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { LangZh } from "@nlpjs/lang-zh";
|
import { LangZh } from "@nlpjs/lang-zh";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import * as fflate from 'fflate';
|
import * as fflate from "fflate";
|
||||||
|
|
||||||
let zh: TrainData = {};
|
let zh: TrainData = {};
|
||||||
let en: TrainData = {};
|
let en: TrainData = {};
|
||||||
@ -61,7 +61,7 @@ export async function trainIntentionModel() {
|
|||||||
const buf = fflate.strToU8(JSON.stringify(resultModel));
|
const buf = fflate.strToU8(JSON.stringify(resultModel));
|
||||||
|
|
||||||
const gzipped = fflate.gzipSync(buf, {
|
const gzipped = fflate.gzipSync(buf, {
|
||||||
filename: 'model.json',
|
filename: "model.json",
|
||||||
mtime: new Date().getTime()
|
mtime: new Date().getTime()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export function keywordSuggestion(query: string) {
|
|||||||
prompt: keyword,
|
prompt: keyword,
|
||||||
relevance: 3000
|
relevance: 3000
|
||||||
};
|
};
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const keyword in dict_en) {
|
for (const keyword in dict_en) {
|
||||||
@ -32,7 +32,7 @@ export function keywordSuggestion(query: string) {
|
|||||||
prompt: keyword,
|
prompt: keyword,
|
||||||
relevance: 3000
|
relevance: 3000
|
||||||
};
|
};
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -1 +1,9 @@
|
|||||||
export const engineTranslation = ["google", "bing", "baidu", "duckduckgo", "yandex", "ecosia", "yahoo"];
|
export const engineTranslation = [
|
||||||
|
"google",
|
||||||
|
"bing",
|
||||||
|
"baidu",
|
||||||
|
"duckduckgo",
|
||||||
|
"yandex",
|
||||||
|
"ecosia",
|
||||||
|
"yahoo"
|
||||||
|
];
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
import { settingsType } from "global";
|
import { settingsType } from "global";
|
||||||
import { atomWithStorage } from 'jotai/utils'
|
import { atomWithStorage } from "jotai/utils";
|
||||||
|
|
||||||
const defaultSettings: settingsType = {
|
const defaultSettings: settingsType = {
|
||||||
"version": 2,
|
version: 2,
|
||||||
"elementBackdrop": true,
|
elementBackdrop: true,
|
||||||
"bgBlur": true,
|
bgBlur: true,
|
||||||
"timeShowSecond": false,
|
timeShowSecond: false,
|
||||||
"currentSearchEngine": "google",
|
currentSearchEngine: "google",
|
||||||
"searchInNewTab": true,
|
searchInNewTab: true,
|
||||||
"searchEngines": {
|
searchEngines: {
|
||||||
"google": "https://www.google.com/search?q=%s",
|
google: "https://www.google.com/search?q=%s",
|
||||||
"bing": "https://www.bing.com/search?q=%s",
|
bing: "https://www.bing.com/search?q=%s",
|
||||||
"baidu": "https://www.baidu.com/s?wd=%s",
|
baidu: "https://www.baidu.com/s?wd=%s",
|
||||||
"duckduckgo": "https://duckduckgo.com/?q=%s",
|
duckduckgo: "https://duckduckgo.com/?q=%s",
|
||||||
"yandex": "https://yandex.com/search/?text=%s",
|
yandex: "https://yandex.com/search/?text=%s",
|
||||||
"yahoo": "https://search.yahoo.com/search?p=%s",
|
yahoo: "https://search.yahoo.com/search?p=%s",
|
||||||
"ecosia": "https://www.ecosia.org/search?q=%s"
|
ecosia: "https://www.ecosia.org/search?q=%s"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const settingsAtom = atomWithStorage('settings', defaultSettings);
|
const settingsAtom = atomWithStorage("settings", defaultSettings);
|
||||||
|
|
||||||
export { settingsAtom };
|
export { settingsAtom };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import pjson from "package.json"
|
import pjson from "package.json";
|
||||||
|
|
||||||
const CLIENT_VERSION = pjson.version;
|
const CLIENT_VERSION = pjson.version;
|
||||||
|
|
||||||
@ -17,5 +17,5 @@ export function sendError(error: Error) {
|
|||||||
cause: error.cause,
|
cause: error.cause,
|
||||||
stack: error.stack
|
stack: error.stack
|
||||||
})
|
})
|
||||||
})
|
});
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import TLDtxt from "./tlds.txt?raw"
|
import TLDtxt from "./tlds.txt?raw";
|
||||||
|
|
||||||
export function getTLD() {
|
export function getTLD() {
|
||||||
return TLDtxt.split("\n").filter((line) => line[0] !== "#")
|
return TLDtxt.split("\n").filter((line) => line[0] !== "#");
|
||||||
}
|
}
|
@ -4,9 +4,9 @@ export function getClosestHourTimestamp(): string {
|
|||||||
|
|
||||||
// 获取本地时间的年份、月份、日期、小时
|
// 获取本地时间的年份、月份、日期、小时
|
||||||
const year = now.getFullYear();
|
const year = now.getFullYear();
|
||||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
|
const month = String(now.getMonth() + 1).padStart(2, "0"); // 月份从0开始
|
||||||
const day = String(now.getDate()).padStart(2, '0');
|
const day = String(now.getDate()).padStart(2, "0");
|
||||||
const hour = String(now.getHours()).padStart(2, '0');
|
const hour = String(now.getHours()).padStart(2, "0");
|
||||||
|
|
||||||
// 拼接成所需的格式
|
// 拼接成所需的格式
|
||||||
const localHourTimestamp = `${year}-${month}-${day}T${hour}:00`;
|
const localHourTimestamp = `${year}-${month}-${day}T${hour}:00`;
|
||||||
|
@ -3,15 +3,16 @@ export async function getWeather(lat: number, lon: number) {
|
|||||||
const cacheKey = `weather-cache-${lat.toFixed(2)}-${lon.toFixed(2)}-${timezone}`;
|
const cacheKey = `weather-cache-${lat.toFixed(2)}-${lon.toFixed(2)}-${timezone}`;
|
||||||
const localData = localStorage.getItem(cacheKey);
|
const localData = localStorage.getItem(cacheKey);
|
||||||
if (localData != null) {
|
if (localData != null) {
|
||||||
console.log('Using cache');
|
console.log("Using cache");
|
||||||
const parsedLocalData = JSON.parse(localData);
|
const parsedLocalData = JSON.parse(localData);
|
||||||
if (parsedLocalData["hourly"]["time"][0] != undefined &&
|
if (
|
||||||
new Date().getTime() - new Date(parsedLocalData["hourly"]["time"][0]).getTime() < 86400 * 1000
|
parsedLocalData["hourly"]["time"][0] != undefined &&
|
||||||
|
new Date().getTime() - new Date(parsedLocalData["hourly"]["time"][0]).getTime() <
|
||||||
|
86400 * 1000
|
||||||
) {
|
) {
|
||||||
return parsedLocalData;
|
return parsedLocalData;
|
||||||
}
|
} else {
|
||||||
else {
|
console.log("Cache expired");
|
||||||
console.log('Cache expired');
|
|
||||||
localStorage.removeItem(cacheKey);
|
localStorage.removeItem(cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"build": "bun license-gen && tsc -b && vite build",
|
"build": "bun license-gen && tsc -b && vite build",
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"preview": "NODE_ENV=production bun server.ts",
|
"preview": "NODE_ENV=production bun server.ts",
|
||||||
"license-gen": "bunx generate-license-file --input package.json --output lib/license.txt --overwrite"
|
"license-gen": "bunx generate-license-file --input package.json --output lib/license.txt --overwrite",
|
||||||
|
"format": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/react": "^5.0.1",
|
"@iconify/react": "^5.0.1",
|
||||||
@ -51,6 +52,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"eslint-plugin-react-refresh": "^0.4.7",
|
"eslint-plugin-react-refresh": "^0.4.7",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
"tailwindcss": "^3.4.4",
|
"tailwindcss": "^3.4.4",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^5.3.1",
|
"vite": "^5.3.1",
|
||||||
|
@ -9,7 +9,10 @@ export default function NotFound() {
|
|||||||
<div className="relative h-20 mx-4 w-[0.15rem] bg-black dark:bg-white"></div>
|
<div className="relative h-20 mx-4 w-[0.15rem] bg-black dark:bg-white"></div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="uppercase text-3xl font-light">{t("notfound.title")}</div>
|
<div className="uppercase text-3xl font-light">{t("notfound.title")}</div>
|
||||||
<div className="text-sm" dangerouslySetInnerHTML={{__html:t("notfound.desc")}}></div>
|
<div
|
||||||
|
className="text-sm"
|
||||||
|
dangerouslySetInnerHTML={{ __html: t("notfound.desc") }}
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
export default function AboutLayout({ children }: { children: React.ReactNode }) {
|
export default function AboutLayout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="h-screen w-screen overflow-x-hidden bg-white dark:bg-[rgb(23,25,29)]">
|
<div className="h-screen w-screen overflow-x-hidden bg-white dark:bg-[rgb(23,25,29)]">
|
||||||
<main className="relative h-full w-full md:w-3/4 lg:w-1/2 left-0 md:left-[12.5%] lg:left-1/4
|
<main
|
||||||
pt-12 px-3 md:px-0">
|
className="relative h-full w-full md:w-3/4 lg:w-1/2 left-0 md:left-[12.5%] lg:left-1/4
|
||||||
|
pt-12 px-3 md:px-0"
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,9 +8,7 @@ export default function LicensePage() {
|
|||||||
pt-12"
|
pt-12"
|
||||||
>
|
>
|
||||||
<h1 className="text-4xl font-bold mb-6">LICENSE</h1>
|
<h1 className="text-4xl font-bold mb-6">LICENSE</h1>
|
||||||
<div className="font-mono text-justify whitespace-break-spaces">
|
<div className="font-mono text-justify whitespace-break-spaces">{LICENSE}</div>
|
||||||
{LICENSE}
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
47
server.ts
47
server.ts
@ -6,7 +6,6 @@ import { networkInterfaces } from "os";
|
|||||||
import cac from "cac";
|
import cac from "cac";
|
||||||
import { configureBackendRoutes } from "./backend/route";
|
import { configureBackendRoutes } from "./backend/route";
|
||||||
|
|
||||||
|
|
||||||
async function helloMessage() {
|
async function helloMessage() {
|
||||||
const { base } = await ViteExpress.getViteConfig();
|
const { base } = await ViteExpress.getViteConfig();
|
||||||
const timeCost = new Date().getTime() - start.getTime();
|
const timeCost = new Date().getTime() - start.getTime();
|
||||||
@ -19,13 +18,29 @@ async function helloMessage() {
|
|||||||
`${Math.round(timeCost)} ms`
|
`${Math.round(timeCost)} ms`
|
||||||
);
|
);
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(" ", chalk.redBright("➜ "), "Local:\t", chalk.cyan(`http://${host}:${port}${base}`));
|
console.log(
|
||||||
|
" ",
|
||||||
|
chalk.redBright("➜ "),
|
||||||
|
"Local:\t",
|
||||||
|
chalk.cyan(`http://${host}:${port}${base}`)
|
||||||
|
);
|
||||||
if (host !== "localhost") {
|
if (host !== "localhost") {
|
||||||
for (const ip of ips) {
|
for (const ip of ips) {
|
||||||
console.log(" ", chalk.redBright("➜ "), "Network:\t", chalk.cyan(`http://${ip}:${port}${base}`));
|
console.log(
|
||||||
|
" ",
|
||||||
|
chalk.redBright("➜ "),
|
||||||
|
"Network:\t",
|
||||||
|
chalk.cyan(`http://${ip}:${port}${base}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(" ", chalk.red("➜ "), chalk.whiteBright("press"), "h + enter", chalk.whiteBright("to show help"))
|
console.log(
|
||||||
|
" ",
|
||||||
|
chalk.red("➜ "),
|
||||||
|
chalk.whiteBright("press"),
|
||||||
|
"h + enter",
|
||||||
|
chalk.whiteBright("to show help")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleInput() {
|
async function handleInput() {
|
||||||
@ -33,8 +48,18 @@ async function handleInput() {
|
|||||||
switch (line) {
|
switch (line) {
|
||||||
case "h":
|
case "h":
|
||||||
console.log(" Shortcuts");
|
console.log(" Shortcuts");
|
||||||
console.log(" ", chalk.whiteBright("press"), "c + enter ", chalk.whiteBright("to clear console"));
|
console.log(
|
||||||
console.log(" ", chalk.whiteBright("press"), "q + enter ", chalk.whiteBright("to quit"));
|
" ",
|
||||||
|
chalk.whiteBright("press"),
|
||||||
|
"c + enter ",
|
||||||
|
chalk.whiteBright("to clear console")
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
" ",
|
||||||
|
chalk.whiteBright("press"),
|
||||||
|
"q + enter ",
|
||||||
|
chalk.whiteBright("to quit")
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "c":
|
case "c":
|
||||||
console.clear();
|
console.clear();
|
||||||
@ -71,11 +96,15 @@ const app = express();
|
|||||||
const port = 3000;
|
const port = 3000;
|
||||||
let host = "localhost";
|
let host = "localhost";
|
||||||
|
|
||||||
cli.option("--host [host]", "Sepcify host name")
|
cli.option("--host [host]", "Sepcify host name");
|
||||||
cli.help()
|
cli.help();
|
||||||
cli.version(pjson.version);
|
cli.version(pjson.version);
|
||||||
const parsed = cli.parse();
|
const parsed = cli.parse();
|
||||||
if (parsed.options.host!==undefined && typeof parsed.options.host == "boolean" && parsed.options.host) {
|
if (
|
||||||
|
parsed.options.host !== undefined &&
|
||||||
|
typeof parsed.options.host == "boolean" &&
|
||||||
|
parsed.options.host
|
||||||
|
) {
|
||||||
host = "0.0.0.0";
|
host = "0.0.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
src/i18n.ts
28
src/i18n.ts
@ -1,18 +1,18 @@
|
|||||||
import * as en from "i18n/en.json"
|
import * as en from "i18n/en.json";
|
||||||
import * as zh from "i18n/zh.json"
|
import * as zh from "i18n/zh.json";
|
||||||
import * as ja from "i18n/ja.json"
|
import * as ja from "i18n/ja.json";
|
||||||
import * as ar from "i18n/ar.json"
|
import * as ar from "i18n/ar.json";
|
||||||
import * as de from "i18n/de.json"
|
import * as de from "i18n/de.json";
|
||||||
import * as es from "i18n/es.json"
|
import * as es from "i18n/es.json";
|
||||||
import * as fr from "i18n/fr.json"
|
import * as fr from "i18n/fr.json";
|
||||||
import * as it from "i18n/it.json"
|
import * as it from "i18n/it.json";
|
||||||
import * as ko from "i18n/ko.json"
|
import * as ko from "i18n/ko.json";
|
||||||
import * as pt from "i18n/pt.json"
|
import * as pt from "i18n/pt.json";
|
||||||
import * as ru from "i18n/ru.json"
|
import * as ru from "i18n/ru.json";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
import LanguageDetector from "i18next-browser-languagedetector";
|
||||||
import ICU from 'i18next-icu';
|
import ICU from "i18next-icu";
|
||||||
i18n.use(initReactI18next) // passes i18n down to react-i18next
|
i18n.use(initReactI18next) // passes i18n down to react-i18next
|
||||||
.use(LanguageDetector)
|
.use(LanguageDetector)
|
||||||
.use(ICU)
|
.use(ICU)
|
||||||
@ -59,7 +59,7 @@ i18n.use(initReactI18next) // passes i18n down to react-i18next
|
|||||||
},
|
},
|
||||||
|
|
||||||
detection: {
|
detection: {
|
||||||
order: ['navigator'],
|
order: ["navigator"],
|
||||||
caches: []
|
caches: []
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -8,9 +8,13 @@ describe("Check if a string is an accessible domain/URL/IP", () => {
|
|||||||
// With https and path
|
// With https and path
|
||||||
expect(validLink("https://jestjs.io/docs/getting-started/")).toBe(true);
|
expect(validLink("https://jestjs.io/docs/getting-started/")).toBe(true);
|
||||||
// With anchor
|
// With anchor
|
||||||
expect(validLink("https://difftastic.wilfred.me.uk/zh-CN/git.html#git-difftool")).toBe(true);
|
expect(validLink("https://difftastic.wilfred.me.uk/zh-CN/git.html#git-difftool")).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
// With params
|
// With params
|
||||||
expect(validLink("https://www.bilibili.com/list/ml2252204359?oid=990610203&bvid=BV1sx4y1g7Hh")).toBe(true);
|
expect(
|
||||||
|
validLink("https://www.bilibili.com/list/ml2252204359?oid=990610203&bvid=BV1sx4y1g7Hh")
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
test("Punycode URL", () => {
|
test("Punycode URL", () => {
|
||||||
expect(validLink("https://原神大学.com/")).toBe(true);
|
expect(validLink("https://原神大学.com/")).toBe(true);
|
||||||
@ -48,7 +52,7 @@ describe("Check if the given TLD exist and assigned.", () => {
|
|||||||
// they really exist!
|
// they really exist!
|
||||||
expect(validTLD("example.foo")).toBe(true);
|
expect(validTLD("example.foo")).toBe(true);
|
||||||
expect(validTLD("example.bar")).toBe(true);
|
expect(validTLD("example.bar")).toBe(true);
|
||||||
expect(validTLD('example.zip')).toBe(true);
|
expect(validTLD("example.zip")).toBe(true);
|
||||||
});
|
});
|
||||||
test("Exist but not assigned TLD", () => {
|
test("Exist but not assigned TLD", () => {
|
||||||
expect(validTLD("example.active")).toBe(false);
|
expect(validTLD("example.active")).toBe(false);
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react-swc";
|
import react from "@vitejs/plugin-react-swc";
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from "vite-tsconfig-paths";
|
||||||
import { chunkSplitPlugin } from 'vite-plugin-chunk-split';
|
import { chunkSplitPlugin } from "vite-plugin-chunk-split";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [react(), tsconfigPaths(), chunkSplitPlugin()]
|
||||||
react(),
|
|
||||||
tsconfigPaths(),
|
|
||||||
chunkSplitPlugin()
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user