Skip to content

Commit 2568fda

Browse files
committed
first commit
0 parents  commit 2568fda

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3133
-0
lines changed

‎.gitignore‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
.yarn/install-state.gz
8+
9+
# testing
10+
/coverage
11+
12+
# next.js
13+
/.next/
14+
/out/
15+
16+
# production
17+
/build
18+
19+
# misc
20+
.DS_Store
21+
*.pem
22+
23+
# debug
24+
npm-debug.log*
25+
yarn-debug.log*
26+
yarn-error.log*
27+
28+
# local env files
29+
.env*.local
30+
.dev.vars
31+
32+
33+
# vercel
34+
.vercel
35+
36+
#wrangler
37+
.wrangler
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Quill Zhou
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## Looq
2+
A SearxNG frontend

‎biome.json‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
3+
"organizeImports": {
4+
"enabled": true
5+
},
6+
"linter": {
7+
"enabled": true,
8+
"rules": {
9+
"recommended": true,
10+
"suspicious": {
11+
"noExplicitAny": "off",
12+
"noArrayIndexKey": "off"
13+
}
14+
}
15+
}
16+
}

‎bun.lockb‎

335 KB
Binary file not shown.

‎components.json‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "default",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.js",
8+
"css": "src/styles/globals.less",
9+
"baseColor": "slate",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "src/components",
15+
"utils": "src/lib/utils"
16+
}
17+
}

‎functions/api/[[route]].ts‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { zValidator } from "@hono/zod-validator";
2+
import { Hono } from "hono";
3+
import { env } from "hono/adapter";
4+
import { handle } from "hono/cloudflare-pages";
5+
import { z } from "zod";
6+
7+
const searchSchema = z.object({
8+
q: z.string(),
9+
language: z.string().optional().default("en-US"),
10+
time_range: z.string().optional(),
11+
safesearch: z.string().optional().default("0"),
12+
categories: z.string().optional().default("general"),
13+
});
14+
15+
const autocompleteSchema = z.object({
16+
q: z.string(),
17+
});
18+
19+
const searchResultSchema = z.object({
20+
url: z.string(),
21+
title: z.string(),
22+
content: z.string().optional(),
23+
engine: z.string(),
24+
engines: z.array(z.string()),
25+
positions: z.array(z.number()),
26+
score: z.number(),
27+
category: z.string(),
28+
});
29+
30+
const searchDataResponseSchema = z.object({
31+
query: z.string(),
32+
number_of_results: z.number(),
33+
results: z.array(searchResultSchema),
34+
infoboxes: z
35+
.array(
36+
z.object({
37+
infobox: z.string(),
38+
content: z.string().optional(),
39+
urls: z.array(
40+
z.object({
41+
title: z.string(),
42+
url: z.string(),
43+
}),
44+
),
45+
}),
46+
)
47+
.optional(),
48+
suggestions: z.array(z.string()).optional(),
49+
});
50+
51+
const autoCompleteResponseSchema = z.tuple([z.string(), z.array(z.string())]);
52+
53+
const fetchSearchResults = async ({
54+
query,
55+
baseUrl,
56+
}: { query: z.infer<typeof searchSchema>; baseUrl: string }) => {
57+
const searchParams = new URLSearchParams(
58+
query as { [key: string]: string },
59+
).toString();
60+
const searchUrl = `${baseUrl}/search?${searchParams}&format=json`;
61+
62+
const response = await fetch(searchUrl, {
63+
headers: {
64+
"Content-Type": "application/json",
65+
},
66+
});
67+
const data = await response.json();
68+
const searchDataResponse = searchDataResponseSchema.parse(data);
69+
return searchDataResponse;
70+
};
71+
72+
const fetchAutocompleteResults = async ({
73+
query,
74+
baseUrl,
75+
}: { query: z.infer<typeof autocompleteSchema>; baseUrl: string }) => {
76+
const searchParams = new URLSearchParams(query).toString();
77+
const searchUrl = `${baseUrl}/autocompleter?${searchParams}`;
78+
79+
const response = await fetch(searchUrl, {
80+
headers: {
81+
"Content-Type": "application/json",
82+
},
83+
});
84+
const data = await response.json();
85+
const autoCompleteResponse = autoCompleteResponseSchema.parse(data);
86+
return autoCompleteResponse;
87+
};
88+
89+
const app = new Hono()
90+
.basePath("/api")
91+
.get("/search", zValidator("query", searchSchema), async (c) => {
92+
const query = c.req.valid("query");
93+
const { SEARXNG_URL } = env<Record<string, string>>(c);
94+
try {
95+
const data = await fetchSearchResults({ query, baseUrl: SEARXNG_URL });
96+
return c.json(data);
97+
} catch (e: any) {
98+
console.error(e);
99+
return c.json({ error: e.message }, 500);
100+
}
101+
})
102+
.get("/autocompleter", zValidator("query", autocompleteSchema), async (c) => {
103+
const query = c.req.valid("query");
104+
const { SEARXNG_URL } = env<Record<string, string>>(c);
105+
try {
106+
const data = await fetchAutocompleteResults({
107+
query,
108+
baseUrl: SEARXNG_URL,
109+
});
110+
return c.json(data);
111+
} catch (e: any) {
112+
console.error(e);
113+
return c.json({ error: e.message }, 500);
114+
}
115+
});
116+
117+
type AppType = typeof app;
118+
119+
export const onRequest = handle(app);
120+
121+
export type { AppType };
122+
123+
export {
124+
searchSchema,
125+
autocompleteSchema,
126+
searchResultSchema,
127+
searchDataResponseSchema,
128+
autoCompleteResponseSchema,
129+
};

‎index.html‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html class="dark">
3+
<head>
4+
<meta http-equiv="content-type" content="text/html; charset=utf-8">
5+
<meta charset="UTF-8">
6+
<link rel="icon" href="/favicon.ico" type="image/x-icon">
7+
<meta property="og:image" content="/og-image.jpeg" />
8+
<meta property="og:title" content="Looq">
9+
<meta property="og:site_name" content="Looq">
10+
<meta property="og:description" content="Search">
11+
12+
<meta name="twitter:card" content="summary_large_image">
13+
<meta name="twitter:image:alt" content="Looq">
14+
<meta name="twitter:title" content="Looq">
15+
<meta name="twitter:description" content="Search">
16+
<meta name="twitter:image:src" content="/og-image.jpeg">
17+
18+
<meta name="description" content="Looq">
19+
<meta name="keywords" content="vite,react,typescript,tailwindcss,template,starter,boilerplate">
20+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
21+
<meta name="theme-color" content="#000000" />
22+
<title></title>
23+
</head>
24+
<body class="bg-background text-foreground">
25+
<div id="root"></div>
26+
<script type="module" src="/src/main.tsx"></script>
27+
</body>
28+
</html>

‎package.json‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"name": "looq",
3+
"private": true,
4+
"version": "0.0.0",
5+
"scripts": {
6+
"prepare": "husky install",
7+
"dev": "wrangler pages dev --local -- bun vite --proxy 5000",
8+
"dev:wrangler": "wrangler pages dev --local",
9+
"dev:vite": "vite",
10+
"start:wrangler": "wrangler pages dev",
11+
"start:vite": "vite preview --port 5000",
12+
"build": "npm run typecheck && vite build",
13+
"typecheck": "tsc --noEmit",
14+
"typecheck:watch": "tsc --noEmit --watch",
15+
"lint": "biome check",
16+
"i18next-resources-for-ts": "i18next-resources-for-ts toc -i ./src/i18n/locales/en -o ./src/types/resources.ts",
17+
"translate": "transmart"
18+
},
19+
"dependencies": {
20+
"@hono/zod-validator": "^0.2.2",
21+
"@hookform/resolvers": "^3.9.0",
22+
"@loadable/component": "^5.16.4",
23+
"@radix-ui/react-accordion": "^1.2.0",
24+
"@radix-ui/react-alert-dialog": "^1.1.1",
25+
"@radix-ui/react-avatar": "^1.1.0",
26+
"@radix-ui/react-checkbox": "^1.1.1",
27+
"@radix-ui/react-collapsible": "^1.1.0",
28+
"@radix-ui/react-dialog": "^1.1.1",
29+
"@radix-ui/react-label": "^2.1.0",
30+
"@radix-ui/react-navigation-menu": "^1.2.0",
31+
"@radix-ui/react-popover": "^1.1.1",
32+
"@radix-ui/react-select": "^2.1.1",
33+
"@radix-ui/react-separator": "^1.1.0",
34+
"@radix-ui/react-slot": "^1.1.0",
35+
"@radix-ui/react-toggle": "^1.1.0",
36+
"@radix-ui/react-tooltip": "^1.1.2",
37+
"@tanstack/react-query": "^5.55.0",
38+
"@transmart/cli": "^0.5.1",
39+
"class-variance-authority": "^0.7.0",
40+
"clsx": "^2.1.1",
41+
"cmdk": "1.0.0",
42+
"i18next": "^23.14.0",
43+
"i18next-browser-languagedetector": "^8.0.0",
44+
"i18next-resources-to-backend": "^1.2.1",
45+
"lucide-react": "^0.439.0",
46+
"next-themes": "^0.3.0",
47+
"react": "^18.3.1",
48+
"react-dom": "^18.3.1",
49+
"react-helmet": "^6.1.0",
50+
"react-hook-form": "^7.53.0",
51+
"react-i18next": "^15.0.1",
52+
"react-router-dom": "^6.26.1",
53+
"sonner": "^1.5.0",
54+
"tailwind-merge": "^2.5.2",
55+
"tailwindcss-animate": "^1.0.7",
56+
"wrangler": "^3.75.0",
57+
"zod": "^3.23.8"
58+
},
59+
"devDependencies": {
60+
"@biomejs/biome": "1.8.3",
61+
"@commitlint/cli": "^19.4.1",
62+
"@commitlint/config-conventional": "^19.4.1",
63+
"@tanstack/react-query-devtools": "^5.55.0",
64+
"@types/loadable__component": "^5.13.9",
65+
"@types/react": "^18.3.5",
66+
"@types/react-dom": "^18.3.0",
67+
"@types/react-helmet": "^6.1.11",
68+
"@typescript-eslint/eslint-plugin": "^8.4.0",
69+
"@typescript-eslint/parser": "^8.4.0",
70+
"@vitejs/plugin-react": "^4.3.1",
71+
"autoprefixer": "^10.4.20",
72+
"eslint": "^9.9.1",
73+
"eslint-config-prettier": "^9.1.0",
74+
"eslint-import-resolver-typescript": "^3.6.3",
75+
"eslint-plugin-import": "^2.30.0",
76+
"eslint-plugin-prettier": "^5.2.1",
77+
"eslint-plugin-react": "^7.35.2",
78+
"eslint-plugin-react-hooks": "^4.6.2",
79+
"eslint-plugin-unused-imports": "^4.1.3",
80+
"husky": "^9.1.5",
81+
"i18next-resources-for-ts": "1.5.0",
82+
"less": "^4.2.0",
83+
"lint-staged": "^15.2.10",
84+
"postcss": "^8.4.45",
85+
"postcss-less": "^6.0.0",
86+
"prettier": "^3.3.3",
87+
"prettier-plugin-tailwindcss": "^0.6.6",
88+
"stylelint": "^16.9.0",
89+
"stylelint-config-standard": "^36.0.1",
90+
"stylelint-less": "^3.0.1",
91+
"stylelint-prettier": "5",
92+
"tailwindcss": "^3.4.10",
93+
"ts-node": "^10.9.2",
94+
"typescript": "^5.5.4",
95+
"vite": "^5.4.3",
96+
"vite-plugin-external": "^4.3.1",
97+
"vite-plugin-svgr": "^4.2.0"
98+
}
99+
}

‎postcss.config.js‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = {
2+
plugins: {
3+
autoprefixer: {
4+
overrideBrowserslist: [
5+
"Android 4.1",
6+
"iOS 7.1",
7+
"Chrome > 31",
8+
"ff > 31",
9+
"ie >= 8",
10+
"last 10 versions",
11+
],
12+
grid: true,
13+
},
14+
tailwindcss: {},
15+
},
16+
};

0 commit comments

Comments
 (0)