ref: format
This commit is contained in:
parent
35f90b42d9
commit
d97e678206
@ -1,5 +1,5 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"useTabs": true,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": false,
|
||||
|
@ -2,10 +2,10 @@ import { Express } from "express";
|
||||
import { completeGoogle } from "search-engine-autocomplete";
|
||||
|
||||
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 t = parseInt(req.query.t as string || "0") || null;
|
||||
let language = req.query.l as string || 'en-US';
|
||||
const t = parseInt((req.query.t as string) || "0") || null;
|
||||
let language = (req.query.l as string) || "en-US";
|
||||
|
||||
try {
|
||||
const data = await completeGoogle(query, language);
|
||||
@ -13,10 +13,10 @@ export function configureBackendRoutes(app: Express) {
|
||||
res.json({ ...data, time: t });
|
||||
} catch (error) {
|
||||
//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) => {
|
||||
res.status(200).json({message: "pong"});
|
||||
})
|
||||
res.status(200).json({ message: "pong" });
|
||||
});
|
||||
}
|
@ -11,9 +11,19 @@ export default function Background() {
|
||||
return (
|
||||
<div>
|
||||
{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>
|
||||
);
|
||||
|
@ -24,7 +24,11 @@ export default function BackgroundContainer(props: {
|
||||
src={props.src}
|
||||
className={
|
||||
"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"
|
||||
onClick={props.onClick}
|
||||
|
@ -6,16 +6,14 @@ import { WMOCodeTable } from "lib/weather/wmocode";
|
||||
|
||||
type UpdateSuggestionFunction = (data: suggestionItem[]) => void;
|
||||
|
||||
export function handleNLUResult(result: any, updateSuggestion: UpdateSuggestionFunction){
|
||||
export function handleNLUResult(result: any, updateSuggestion: UpdateSuggestionFunction) {
|
||||
if (result.intent == "weather.summary") {
|
||||
getLocationNative((data: GeolocationCoordinates | GeolocationPositionError) => {
|
||||
console.log(data);
|
||||
if (data instanceof GeolocationCoordinates) {
|
||||
getWeather(data.latitude, data.longitude).then((weather) => {
|
||||
console.log(weather["hourly"]);
|
||||
let hourIndex = findClosestDateIndex(
|
||||
weather["hourly"]["time"]
|
||||
);
|
||||
let hourIndex = findClosestDateIndex(weather["hourly"]["time"]);
|
||||
let temp = weather["hourly"]["apparent_temperature"][hourIndex];
|
||||
let weatherCode = weather["hourly"]["weather_code"][hourIndex];
|
||||
console.log(temp, weatherCode, hourIndex);
|
||||
|
@ -2,7 +2,11 @@ import { useAtomValue } from "jotai";
|
||||
import search from "lib/search";
|
||||
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 engine = settings.searchEngines[settings.currentSearchEngine];
|
||||
const newTab = settings.searchInNewTab;
|
||||
@ -18,8 +22,7 @@ export default function PlainSearch(props: { children: React.ReactNode; query: s
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
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 }) {
|
||||
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;
|
||||
|
||||
return createPortal(
|
||||
<div className="absolute w-screen h-screen" onClick={()=>{toggleDisplay(false)}}>
|
||||
<div
|
||||
className="absolute w-screen h-screen"
|
||||
onClick={() => {
|
||||
toggleDisplay(false);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
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 default function SelectionItem(props: {key: selectionType, children: ReactNode, onChange: selectedOnChange}){
|
||||
return (
|
||||
<div onClick={() => props.onChange(props.key)}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
export default function SelectionItem(props: {
|
||||
key: selectionType;
|
||||
children: ReactNode;
|
||||
onChange: selectedOnChange;
|
||||
}) {
|
||||
return <div onClick={() => props.onChange(props.key)}>{props.children}</div>;
|
||||
}
|
@ -2,9 +2,7 @@
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export default function Time(props: {
|
||||
showSecond: boolean
|
||||
}) {
|
||||
export default function Time(props: { showSecond: boolean }) {
|
||||
const [currentTime, setCurrentTime] = useState(new Date());
|
||||
|
||||
useEffect(() => {
|
||||
|
48
global.d.ts
vendored
48
global.d.ts
vendored
@ -1,31 +1,31 @@
|
||||
import { Suggestion } from "search-engine-autocomplete";
|
||||
|
||||
interface settingsType extends object{
|
||||
"version": number,
|
||||
"elementBackdrop": boolean,
|
||||
"bgBlur": boolean,
|
||||
"timeShowSecond": boolean,
|
||||
"currentSearchEngine": string,
|
||||
"searchInNewTab": boolean,
|
||||
"searchEngines": {
|
||||
[key: string]: string
|
||||
},
|
||||
interface settingsType extends object {
|
||||
version: number;
|
||||
elementBackdrop: boolean;
|
||||
bgBlur: boolean;
|
||||
timeShowSecond: boolean;
|
||||
currentSearchEngine: string;
|
||||
searchInNewTab: boolean;
|
||||
searchEngines: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface suggestionsResponse extends object{
|
||||
suggestions: Suggestion[],
|
||||
query: string,
|
||||
verbatimRelevance: number,
|
||||
time: number
|
||||
interface suggestionsResponse extends object {
|
||||
suggestions: Suggestion[];
|
||||
query: string;
|
||||
verbatimRelevance: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
type suggestionItem = {
|
||||
suggestion: string,
|
||||
type: string,
|
||||
relativeRelevance?: number,
|
||||
relevance: number,
|
||||
prompt?: string | React.ReactElement,
|
||||
intention?: string | null,
|
||||
probability?: number,
|
||||
confidence?: number,
|
||||
}
|
||||
suggestion: string;
|
||||
type: string;
|
||||
relativeRelevance?: number;
|
||||
relevance: number;
|
||||
prompt?: string | React.ReactElement;
|
||||
intention?: string | null;
|
||||
probability?: number;
|
||||
confidence?: number;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "ابحث أو اكتب عنوان URL"
|
||||
"search": {
|
||||
"placeholder": "ابحث أو اكتب عنوان URL"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Suche oder gib eine URL ein"
|
||||
"search": {
|
||||
"placeholder": "Suche oder gib eine URL ein"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Buscar o escribir una URL"
|
||||
"search": {
|
||||
"placeholder": "Buscar o escribir una URL"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Rechercher ou saisir une URL"
|
||||
"search": {
|
||||
"placeholder": "Rechercher ou saisir une URL"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Cerca o digita un URL"
|
||||
"search": {
|
||||
"placeholder": "Cerca o digita un URL"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "검색 또는 URL 입력"
|
||||
"search": {
|
||||
"placeholder": "검색 또는 URL 입력"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Pesquisar ou digitar uma URL"
|
||||
"search": {
|
||||
"placeholder": "Pesquisar ou digitar uma URL"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"search" : {
|
||||
"placeholder" : "Искать или ввести URL"
|
||||
"search": {
|
||||
"placeholder": "Искать или ввести URL"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
export default function copyToClipboard(value: string){
|
||||
export default function copyToClipboard(value: string) {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = value;
|
||||
document.body.appendChild(textarea);
|
||||
|
@ -137,11 +137,5 @@
|
||||
"Which framework do you think is the most suitable for performance sensitive projects?"
|
||||
],
|
||||
|
||||
"None": [
|
||||
"free weather api",
|
||||
"js get timezone",
|
||||
"how",
|
||||
"how's",
|
||||
"how's the"
|
||||
]
|
||||
"None": ["free weather api", "js get timezone", "how", "how's", "how's the"]
|
||||
}
|
||||
|
@ -117,11 +117,5 @@
|
||||
"HTML实体转文本:%s"
|
||||
],
|
||||
|
||||
"None": [
|
||||
"你好",
|
||||
"为什么计算机使用二进制",
|
||||
"什么是",
|
||||
"热",
|
||||
"怎么"
|
||||
]
|
||||
"None": ["你好", "为什么计算机使用二进制", "什么是", "热", "怎么"]
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import { NluManager, NluNeural } from "@nlpjs/nlu";
|
||||
import { LangEn } from "@nlpjs/lang-en-min";
|
||||
// @ts-ignore
|
||||
import { LangZh } from "@nlpjs/lang-zh";
|
||||
import * as fflate from 'fflate';
|
||||
import * as fflate from "fflate";
|
||||
|
||||
export interface NLUType {
|
||||
manager: any;
|
||||
@ -18,7 +18,6 @@ export interface NLUType {
|
||||
process(lang: string, text: string): Promise<any>;
|
||||
}
|
||||
|
||||
|
||||
export class NLU {
|
||||
manager: any;
|
||||
inited: boolean = false;
|
||||
|
@ -9,7 +9,7 @@ import { LangEn } from "@nlpjs/lang-en-min";
|
||||
// @ts-ignore
|
||||
import { LangZh } from "@nlpjs/lang-zh";
|
||||
import fs from "node:fs";
|
||||
import * as fflate from 'fflate';
|
||||
import * as fflate from "fflate";
|
||||
|
||||
let zh: TrainData = {};
|
||||
let en: TrainData = {};
|
||||
@ -61,7 +61,7 @@ export async function trainIntentionModel() {
|
||||
const buf = fflate.strToU8(JSON.stringify(resultModel));
|
||||
|
||||
const gzipped = fflate.gzipSync(buf, {
|
||||
filename: 'model.json',
|
||||
filename: "model.json",
|
||||
mtime: new Date().getTime()
|
||||
});
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { settingsType } from "global";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function(){
|
||||
export default function () {
|
||||
const settings: settingsType = useAtomValue(settingsAtom);
|
||||
const currentEngine = settings.currentSearchEngine;
|
||||
const displayEngine = getName(currentEngine);
|
||||
|
@ -21,7 +21,7 @@ export function keywordSuggestion(query: string) {
|
||||
prompt: keyword,
|
||||
relevance: 3000
|
||||
};
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (const keyword in dict_en) {
|
||||
@ -32,7 +32,7 @@ export function keywordSuggestion(query: string) {
|
||||
prompt: keyword,
|
||||
relevance: 3000
|
||||
};
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
}
|
||||
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,4 +1,4 @@
|
||||
export default function(query: string, engine: string, newTab: boolean = true) {
|
||||
if(newTab) window.open(engine.replace("%s", query));
|
||||
export default function (query: string, engine: string, newTab: boolean = true) {
|
||||
if (newTab) window.open(engine.replace("%s", query));
|
||||
else window.location.href = engine.replace("%s", query);
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
import { settingsType } from "global";
|
||||
import { atomWithStorage } from 'jotai/utils'
|
||||
import { atomWithStorage } from "jotai/utils";
|
||||
|
||||
const defaultSettings: settingsType = {
|
||||
"version": 2,
|
||||
"elementBackdrop": true,
|
||||
"bgBlur": true,
|
||||
"timeShowSecond": false,
|
||||
"currentSearchEngine": "google",
|
||||
"searchInNewTab": true,
|
||||
"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",
|
||||
"yahoo": "https://search.yahoo.com/search?p=%s",
|
||||
"ecosia": "https://www.ecosia.org/search?q=%s"
|
||||
version: 2,
|
||||
elementBackdrop: true,
|
||||
bgBlur: true,
|
||||
timeShowSecond: false,
|
||||
currentSearchEngine: "google",
|
||||
searchInNewTab: true,
|
||||
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",
|
||||
yahoo: "https://search.yahoo.com/search?p=%s",
|
||||
ecosia: "https://www.ecosia.org/search?q=%s"
|
||||
}
|
||||
};
|
||||
|
||||
const settingsAtom = atomWithStorage('settings', defaultSettings);
|
||||
const settingsAtom = atomWithStorage("settings", defaultSettings);
|
||||
|
||||
export { settingsAtom };
|
||||
|
@ -1,4 +1,4 @@
|
||||
import pjson from "package.json"
|
||||
import pjson from "package.json";
|
||||
|
||||
const CLIENT_VERSION = pjson.version;
|
||||
|
||||
@ -11,11 +11,11 @@ export function sendError(error: Error) {
|
||||
body: JSON.stringify({
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
time: new Date().getTime()/1000,
|
||||
time: new Date().getTime() / 1000,
|
||||
version: CLIENT_VERSION,
|
||||
ua: navigator.userAgent,
|
||||
cause: error.cause,
|
||||
stack: error.stack
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import TLDtxt from "./tlds.txt?raw"
|
||||
import TLDtxt from "./tlds.txt?raw";
|
||||
|
||||
export function getTLD(){
|
||||
return TLDtxt.split("\n").filter((line) => line[0] !== "#")
|
||||
export function getTLD() {
|
||||
return TLDtxt.split("\n").filter((line) => line[0] !== "#");
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import * as pjson from "package.json";
|
||||
|
||||
export default function getVersion(){
|
||||
export default function getVersion() {
|
||||
return pjson.version;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@ export function getClosestHourTimestamp(): string {
|
||||
|
||||
// 获取本地时间的年份、月份、日期、小时
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hour = String(now.getHours()).padStart(2, '0');
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0"); // 月份从0开始
|
||||
const day = String(now.getDate()).padStart(2, "0");
|
||||
const hour = String(now.getHours()).padStart(2, "0");
|
||||
|
||||
// 拼接成所需的格式
|
||||
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 localData = localStorage.getItem(cacheKey);
|
||||
if (localData != null) {
|
||||
console.log('Using cache');
|
||||
console.log("Using cache");
|
||||
const parsedLocalData = JSON.parse(localData);
|
||||
if (parsedLocalData["hourly"]["time"][0] != undefined &&
|
||||
new Date().getTime() - new Date(parsedLocalData["hourly"]["time"][0]).getTime() < 86400 * 1000
|
||||
if (
|
||||
parsedLocalData["hourly"]["time"][0] != undefined &&
|
||||
new Date().getTime() - new Date(parsedLocalData["hourly"]["time"][0]).getTime() <
|
||||
86400 * 1000
|
||||
) {
|
||||
return parsedLocalData;
|
||||
}
|
||||
else {
|
||||
console.log('Cache expired');
|
||||
} else {
|
||||
console.log("Cache expired");
|
||||
localStorage.removeItem(cacheKey);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,8 @@
|
||||
"build": "bun license-gen && tsc -b && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"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": {
|
||||
"@iconify/react": "^5.0.1",
|
||||
@ -51,6 +52,7 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^3.3.3",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.2.2",
|
||||
"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="flex flex-col">
|
||||
<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>
|
||||
|
@ -1,8 +1,10 @@
|
||||
export default function AboutLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<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
|
||||
pt-12 px-3 md:px-0">
|
||||
<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
|
||||
pt-12 px-3 md:px-0"
|
||||
>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
|
@ -8,9 +8,7 @@ export default function LicensePage() {
|
||||
pt-12"
|
||||
>
|
||||
<h1 className="text-4xl font-bold mb-6">LICENSE</h1>
|
||||
<div className="font-mono text-justify whitespace-break-spaces">
|
||||
{LICENSE}
|
||||
</div>
|
||||
<div className="font-mono text-justify whitespace-break-spaces">{LICENSE}</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
|
49
server.ts
49
server.ts
@ -6,7 +6,6 @@ import { networkInterfaces } from "os";
|
||||
import cac from "cac";
|
||||
import { configureBackendRoutes } from "./backend/route";
|
||||
|
||||
|
||||
async function helloMessage() {
|
||||
const { base } = await ViteExpress.getViteConfig();
|
||||
const timeCost = new Date().getTime() - start.getTime();
|
||||
@ -19,13 +18,29 @@ async function helloMessage() {
|
||||
`${Math.round(timeCost)} ms`
|
||||
);
|
||||
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") {
|
||||
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() {
|
||||
@ -33,14 +48,24 @@ async function handleInput() {
|
||||
switch (line) {
|
||||
case "h":
|
||||
console.log(" Shortcuts");
|
||||
console.log(" ", chalk.whiteBright("press"), "c + enter ", chalk.whiteBright("to clear console"));
|
||||
console.log(" ", chalk.whiteBright("press"), "q + enter ", chalk.whiteBright("to quit"));
|
||||
console.log(
|
||||
" ",
|
||||
chalk.whiteBright("press"),
|
||||
"c + enter ",
|
||||
chalk.whiteBright("to clear console")
|
||||
);
|
||||
console.log(
|
||||
" ",
|
||||
chalk.whiteBright("press"),
|
||||
"q + enter ",
|
||||
chalk.whiteBright("to quit")
|
||||
);
|
||||
break;
|
||||
case "c":
|
||||
console.clear();
|
||||
break;
|
||||
case "q":
|
||||
server.on("vite:close", ()=>{});
|
||||
server.on("vite:close", () => {});
|
||||
server.close();
|
||||
return;
|
||||
default:
|
||||
@ -71,11 +96,15 @@ const app = express();
|
||||
const port = 3000;
|
||||
let host = "localhost";
|
||||
|
||||
cli.option("--host [host]", "Sepcify host name")
|
||||
cli.help()
|
||||
cli.option("--host [host]", "Sepcify host name");
|
||||
cli.help();
|
||||
cli.version(pjson.version);
|
||||
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";
|
||||
}
|
||||
|
||||
|
28
src/i18n.ts
28
src/i18n.ts
@ -1,18 +1,18 @@
|
||||
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 * 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';
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import ICU from "i18next-icu";
|
||||
i18n.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.use(LanguageDetector)
|
||||
.use(ICU)
|
||||
@ -59,7 +59,7 @@ i18n.use(initReactI18next) // passes i18n down to react-i18next
|
||||
},
|
||||
|
||||
detection: {
|
||||
order: ['navigator'],
|
||||
order: ["navigator"],
|
||||
caches: []
|
||||
}
|
||||
});
|
@ -8,9 +8,13 @@ describe("Check if a string is an accessible domain/URL/IP", () => {
|
||||
// With https and path
|
||||
expect(validLink("https://jestjs.io/docs/getting-started/")).toBe(true);
|
||||
// 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
|
||||
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", () => {
|
||||
expect(validLink("https://原神大学.com/")).toBe(true);
|
||||
@ -48,7 +52,7 @@ describe("Check if the given TLD exist and assigned.", () => {
|
||||
// they really exist!
|
||||
expect(validTLD("example.foo")).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", () => {
|
||||
expect(validTLD("example.active")).toBe(false);
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { chunkSplitPlugin } from 'vite-plugin-chunk-split';
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import { chunkSplitPlugin } from "vite-plugin-chunk-split";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
react(),
|
||||
tsconfigPaths(),
|
||||
chunkSplitPlugin()
|
||||
]
|
||||
plugins: [react(), tsconfigPaths(), chunkSplitPlugin()]
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user