add
This commit is contained in:
parent
ee771ba636
commit
32040f4457
|
@ -2,7 +2,7 @@
|
|||
/** @type {import("eslint").Linter.Config} */
|
||||
module.exports = {
|
||||
ignorePatterns: ["apps/**", "packages/**"],
|
||||
extends: ["@workspace/eslint-config/library.js"],
|
||||
extends: ["@repo/eslint-config/library.js"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: true,
|
||||
|
|
|
@ -34,3 +34,6 @@ npm-debug.log*
|
|||
# Misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
|
||||
packages/db/generated
|
|
@ -38,7 +38,7 @@ Your `globals.css` are already set up to use the components from the `ui` packag
|
|||
To use the components in your app, import them from the `ui` package.
|
||||
|
||||
```tsx
|
||||
import { Button } from '@workspace/ui/components/ui/button';
|
||||
import { Button } from '@repo/ui/components/ui/button';
|
||||
```
|
||||
|
||||
## More Resources
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
To install dependencies:
|
||||
```sh
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
```sh
|
||||
bun run dev
|
||||
```
|
||||
|
||||
open http://localhost:3000
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "backend",
|
||||
"scripts": {
|
||||
"dev": "bun run --hot src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "^9.0.2",
|
||||
"@hono/trpc-server": "^0.3.4",
|
||||
"@hono/zod-validator": "^0.5.0",
|
||||
"@repo/db": "workspace:*",
|
||||
"@trpc/server": "11.1.2",
|
||||
"@types/oidc-provider": "^9.1.0",
|
||||
"hono": "^4.7.10",
|
||||
"ioredis": "5.4.1",
|
||||
"minio": "7.1.3",
|
||||
"node-cron": "^4.0.7",
|
||||
"oidc-provider": "^9.1.1",
|
||||
"zod": "^3.25.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/node": "^22.15.21"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { Client } from '@elastic/elasticsearch';
|
||||
|
||||
export const esClient = new Client({
|
||||
node: process.env.ELASTICSEARCH_NODE || 'http://localhost:9200',
|
||||
auth: {
|
||||
username: process.env.ELASTICSEARCH_USER || 'elastic',
|
||||
password: process.env.ELASTICSEARCH_PASSWORD || 'changeme',
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import { Hono } from 'hono'
|
||||
import { logger } from 'hono/logger'
|
||||
import { contextStorage, getContext } from 'hono/context-storage'
|
||||
import { prettyJSON } from 'hono/pretty-json'
|
||||
|
||||
import { trpcServer } from '@hono/trpc-server'
|
||||
import { appRouter } from './trpc'
|
||||
import Redis from 'ioredis'
|
||||
import redis from './redis'
|
||||
import minioClient from './minio'
|
||||
import { Client } from 'minio'
|
||||
import oidc from './oidc/provider'
|
||||
type Env = {
|
||||
Variables: {
|
||||
redis: Redis
|
||||
minio: Client
|
||||
}
|
||||
}
|
||||
|
||||
const app = new Hono<Env>()
|
||||
|
||||
app.use('*', async (c, next) => {
|
||||
c.set('redis', redis)
|
||||
c.set('minio', minioClient)
|
||||
await next()
|
||||
})
|
||||
app.use('*', async (c, next) => {
|
||||
c.set('redis', redis);
|
||||
await next();
|
||||
});
|
||||
app.use(contextStorage())
|
||||
app.use(prettyJSON()) // With options: prettyJSON({ space: 4 })
|
||||
app.use(logger())
|
||||
app.use(
|
||||
'/trpc/*',
|
||||
trpcServer({
|
||||
router: appRouter,
|
||||
})
|
||||
)
|
||||
|
||||
app.get('/', (c) => {
|
||||
return c.text('Hello Hono!')
|
||||
})
|
||||
app.all('/oidc/*', async (c) => {
|
||||
// 让 oidc-provider 处理请求
|
||||
return await oidc.callback(c.req.raw, c.res.raw);
|
||||
});
|
||||
|
||||
|
||||
export default app
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
// apps/backend/src/minio.ts
|
||||
import { Client } from 'minio'
|
||||
|
||||
const minioClient = new Client({
|
||||
endPoint: process.env.MINIO_ENDPOINT || 'localhost',
|
||||
port: Number(process.env.MINIO_PORT) || 9000,
|
||||
useSSL: process.env.MINIO_USE_SSL === 'true',
|
||||
accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',
|
||||
secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',
|
||||
})
|
||||
|
||||
export default minioClient
|
|
@ -0,0 +1,15 @@
|
|||
import { Configuration } from 'oidc-provider';
|
||||
|
||||
const config: Configuration = {
|
||||
clients: [
|
||||
{
|
||||
client_id: 'example-client',
|
||||
client_secret: 'example-secret',
|
||||
grant_types: ['authorization_code'],
|
||||
redirect_uris: ['http://localhost:3000/cb'],
|
||||
},
|
||||
],
|
||||
// 其他配置项...
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -0,0 +1,6 @@
|
|||
import { Provider } from 'oidc-provider';
|
||||
import config from './config';
|
||||
|
||||
const oidc = new Provider('http://localhost:4000', config);
|
||||
|
||||
export default oidc;
|
|
@ -0,0 +1,10 @@
|
|||
// apps/backend/src/redis.ts
|
||||
import Redis from 'ioredis';
|
||||
|
||||
const redis = new Redis({
|
||||
host: 'localhost', // 根据实际情况配置
|
||||
port: 6379,
|
||||
// password: 'yourpassword', // 如有需要
|
||||
});
|
||||
|
||||
export default redis;
|
|
@ -0,0 +1,15 @@
|
|||
import { z } from 'zod'
|
||||
import { initTRPC } from '@trpc/server'
|
||||
|
||||
const t = initTRPC.create()
|
||||
|
||||
export const publicProcedure = t.procedure
|
||||
export const router = t.router
|
||||
|
||||
export const appRouter = router({
|
||||
hello: publicProcedure.input(z.string().nullish()).query(({ input }) => {
|
||||
return `Hello ${input ?? 'World'}!`
|
||||
}),
|
||||
})
|
||||
|
||||
export type AppRouter = typeof appRouter
|
|
@ -0,0 +1,17 @@
|
|||
import { Hono } from "hono";
|
||||
import { createUser, searchUser } from "./userindex";
|
||||
|
||||
const userRoute = new Hono();
|
||||
|
||||
userRoute.post('/', async (c) => {
|
||||
const user = await c.req.json();
|
||||
const result = await createUser(user);
|
||||
return c.json(result);
|
||||
});
|
||||
|
||||
userRoute.get('/search', async (c) => {
|
||||
const q = c.req.query('q') || '';
|
||||
const result = await searchUser(q);
|
||||
return c.json(result.hits.hits);
|
||||
});
|
||||
export default userRoute;
|
|
@ -0,0 +1,7 @@
|
|||
import { publicProcedure, router } from "../trpc";
|
||||
import { prisma } from "@repo/db";
|
||||
export const userRouter = router({
|
||||
getUser: publicProcedure.query(async ({ ctx }) => {
|
||||
return prisma.user.findMany()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,21 @@
|
|||
import { esClient } from "../elasticsearch";
|
||||
|
||||
const USER_INDEX = 'users';
|
||||
export async function createUser(user: any): Promise<ReturnType<typeof esClient.index>> {
|
||||
return esClient.index({
|
||||
index: USER_INDEX,
|
||||
document: user,
|
||||
});
|
||||
}
|
||||
|
||||
export async function searchUser(query: string): Promise<ReturnType<typeof esClient.search>> {
|
||||
return esClient.search({
|
||||
index: USER_INDEX,
|
||||
query: {
|
||||
multi_match: {
|
||||
query,
|
||||
fields: ['name', 'email'],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "@repo/typescript-config/hono.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@repo/db/*": ["../../packages/db/src/*"],
|
||||
},
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
|
||||
import '@workspace/ui/globals.css';
|
||||
import '@repo/ui/globals.css';
|
||||
|
||||
import { Providers } from '@/components/providers';
|
||||
import type { Metadata } from 'next';
|
||||
|
|
|
@ -1,115 +1,3 @@
|
|||
import { ModeToggle } from '@/components/mode-toggle';
|
||||
import { Button, buttonVariants } from '@workspace/ui/components/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from '@workspace/ui/components/dropdown-menu';
|
||||
import { cn } from '@workspace/ui/lib/utils';
|
||||
import { ChevronDownIcon } from 'lucide-react';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
|
||||
<Image className="dark:invert" src="/next.svg" alt="Next.js logo" width={180} height={38} priority />
|
||||
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2">
|
||||
Get started by editing{' '}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">app/page.tsx</code>.
|
||||
</li>
|
||||
<li>Save and see your changes instantly.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
All the buttons are from the <kbd>ui</kbd> package. The auto complete works as well.
|
||||
</p>
|
||||
|
||||
<pre className="border rounded-sm p-1.5 bg-foreground/10">
|
||||
<code>{`import { Button, buttonVariants } from '@workspace/ui/components/button';
|
||||
import { cn } from '@workspace/ui/lib/utils';`}</code>
|
||||
</pre>
|
||||
|
||||
<ModeToggle />
|
||||
|
||||
<Button size={'sm'}>Click me</Button>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size={'sm'}>
|
||||
Dropdown <ChevronDownIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Item 1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 2</DropdownMenuItem>
|
||||
<DropdownMenuCheckboxItem checked>Item 3</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuCheckboxItem>Item 3</DropdownMenuCheckboxItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>Item 3</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>Item 3.1</DropdownMenuItem>
|
||||
<DropdownMenuItem>Item 3.2</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className={cn(buttonVariants({ size: 'lg' }), 'rounded-full')}
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image className="dark:invert" src="/vercel.svg" alt="Vercel logomark" width={20} height={20} />
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className={cn(buttonVariants({ size: 'lg', variant: 'outline' }), 'rounded-full')}
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image aria-hidden src="/file.svg" alt="File icon" width={16} height={16} />
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image aria-hidden src="/window.svg" alt="Window icon" width={16} height={16} />
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
export default async function Home() {
|
||||
return <div></div>;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"components": "@/components",
|
||||
"hooks": "@/hooks",
|
||||
"lib": "@/lib",
|
||||
"utils": "@workspace/ui/lib/utils",
|
||||
"ui": "@workspace/ui/components"
|
||||
"utils": "@repo/ui/lib/utils",
|
||||
"ui": "@repo/ui/components"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ import * as React from 'react';
|
|||
import { Moon, Sun } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Button } from '@repo/ui/components/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@workspace/ui/components/dropdown-menu';
|
||||
} from '@repo/ui/components/dropdown-menu';
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme } = useTheme();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { nextJsConfig } from "@workspace/eslint-config/next-js"
|
||||
import { nextJsConfig } from "@repo/eslint-config/next-js"
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
export default nextJsConfig
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
transpilePackages: ["@workspace/ui"],
|
||||
transpilePackages: ["@repo/ui"],
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
|
|
|
@ -10,20 +10,30 @@
|
|||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@workspace/ui": "workspace:*",
|
||||
"@repo/client": "workspace:*",
|
||||
"@repo/db": "workspace:*",
|
||||
"@repo/ui": "workspace:*",
|
||||
"@tanstack/react-query": "^5.51.21",
|
||||
"@trpc/client": "11.1.2",
|
||||
"@trpc/react-query": "11.1.2",
|
||||
"@trpc/server": "11.1.2",
|
||||
"@trpc/tanstack-react-query": "11.1.2",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "^1.11.12",
|
||||
"lucide-react": "0.511.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"next": "15.3.2",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0"
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"superjson": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/eslint-config": "workspace:*",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
|
||||
"@types/react": "^19.1.4",
|
||||
"@types/react-dom": "^19.1.5",
|
||||
"@workspace/eslint-config": "workspace:*",
|
||||
"@workspace/typescript-config": "workspace:*",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { default } from '@workspace/ui/postcss.config';
|
||||
export { default } from '@repo/ui/postcss.config';
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { loggerLink, httpBatchLink, createTRPCClient } from '@trpc/client';
|
||||
import { TRPCProvider } from '@repo/client';
|
||||
import { useMemo, useState } from 'react';
|
||||
import superjson from 'superjson';
|
||||
import { AppRouter } from '@repo/backend/trpc';
|
||||
|
||||
export default function QueryProvider({ children }) {
|
||||
// 将accessToken设置为空字符串
|
||||
const accessToken = '';
|
||||
|
||||
// 使用Next.js环境变量
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// Set the default query options including staleTime.
|
||||
const [queryClient] = useState(
|
||||
() =>
|
||||
new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const trpcClient = useMemo(() => {
|
||||
const headers = async () => ({
|
||||
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
||||
});
|
||||
|
||||
const links = [
|
||||
httpBatchLink({
|
||||
url: `${apiUrl}/trpc`,
|
||||
headers,
|
||||
transformer: superjson,
|
||||
}),
|
||||
loggerLink({
|
||||
enabled: (opts) =>
|
||||
(process.env.NODE_ENV === 'development' && typeof window !== 'undefined') ||
|
||||
(opts.direction === 'down' && opts.result instanceof Error),
|
||||
}),
|
||||
];
|
||||
|
||||
return createTRPCClient<AppRouter>({
|
||||
links,
|
||||
});
|
||||
}, [accessToken, apiUrl]);
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
|
||||
{children}
|
||||
</TRPCProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"extends": "@workspace/typescript-config/nextjs.json",
|
||||
"extends": "@repo/typescript-config/nextjs.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@workspace/ui/*": ["../../packages/ui/src/*"]
|
||||
"@repo/backend/*": ["../backend/src/*"],
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@workspace/eslint-config": "workspace:*",
|
||||
"@workspace/typescript-config": "workspace:*",
|
||||
"@repo/eslint-config": "workspace:*",
|
||||
"@repo/typescript-config": "workspace:*",
|
||||
"prettier": "^3.5.3",
|
||||
"turbo": "^2.5.3",
|
||||
"typescript": "5.8.3"
|
||||
"typescript": "5.8.3",
|
||||
"@types/node": "^20"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.3",
|
||||
"engines": {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "@repo/client",
|
||||
"version": "1.0.0",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"dev": "tsup --watch",
|
||||
"dev-static": "tsup --no-watch",
|
||||
"clean": "rimraf dist",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/query-async-storage-persister": "^5.51.9",
|
||||
"@tanstack/react-query": "^5.51.21",
|
||||
"@tanstack/react-query-persist-client": "^5.51.9",
|
||||
"@trpc/client": "11.1.2",
|
||||
"@trpc/react-query": "11.1.2",
|
||||
"@trpc/server": "11.1.2",
|
||||
"@trpc/tanstack-react-query": "11.1.2",
|
||||
"axios": "^1.7.2",
|
||||
"dayjs": "^1.11.12",
|
||||
"react": "^19.1.0"
|
||||
|
||||
},
|
||||
"devDependencies": {
|
||||
"rimraf": "^6.0.1",
|
||||
"tsup": "^8.3.5",
|
||||
"@types/react": "^19.1.4",
|
||||
"@types/react-dom": "^19.1.5"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export * from "./useEntity"
|
|
@ -0,0 +1,115 @@
|
|||
import { useTRPC, type RouterInputs, type RouterOutputs } from "../trpc";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useMutation, type UseMutationResult } from "@tanstack/react-query";
|
||||
/**
|
||||
* 定义 MutationType 类型,用于提取指定实体类型的特定 mutation 方法名。
|
||||
* @template T - 实体类型的键名(如 'post', 'user')
|
||||
* @description 该类型通过遍历 RouterInputs[T] 的键名,筛选出符合条件的 mutation 方法名(如 'create', 'update' 等)。
|
||||
*/
|
||||
type MutationType<T extends keyof RouterInputs> = keyof {
|
||||
[K in keyof RouterInputs[T]]: K extends
|
||||
| "create"
|
||||
| "update"
|
||||
| "deleteMany"
|
||||
| "softDeleteByIds"
|
||||
| "restoreByIds"
|
||||
| "updateOrder"
|
||||
? RouterInputs[T][K]
|
||||
: never;
|
||||
};
|
||||
/**
|
||||
* 定义 MutationOptions 类型,用于配置特定 mutation 方法的回调函数。
|
||||
* @template T - 实体类型的键名
|
||||
* @template K - mutation 方法名
|
||||
* @description 该类型包含一个可选的 onSuccess 回调函数,用于在 mutation 成功时执行。
|
||||
*/
|
||||
type MutationOptions<
|
||||
T extends keyof RouterInputs,
|
||||
K extends MutationType<T>,
|
||||
> = {
|
||||
onSuccess?: (
|
||||
data: RouterOutputs[T][K], // mutation 成功后的返回数据
|
||||
variables: RouterInputs[T][K], // mutation 的输入参数
|
||||
context?: unknown // 可选的上下文信息
|
||||
) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* 定义 EntityOptions 类型,用于配置实体类型的所有 mutation 方法的回调函数。
|
||||
* @template T - 实体类型的键名
|
||||
* @description 该类型是一个对象,键为 mutation 方法名,值为对应的 MutationOptions 配置。
|
||||
*/
|
||||
type EntityOptions<T extends keyof RouterInputs> = {
|
||||
[K in MutationType<T>]?: MutationOptions<T, K>;
|
||||
};
|
||||
|
||||
/**
|
||||
* 工具类型:更新为 TanStack Query 的 UseMutationResult 类型。
|
||||
* @template T - 实体类型的键名
|
||||
* @template K - mutation 方法名
|
||||
* @description 该类型用于定义 mutation 函数的返回类型,适配新版 tRPC。
|
||||
*/
|
||||
export type MutationResult<
|
||||
T extends keyof RouterInputs,
|
||||
K extends MutationType<T>,
|
||||
> = UseMutationResult<
|
||||
RouterOutputs[T][K], // mutation 成功后的返回数据
|
||||
Error, // mutation 的错误类型
|
||||
RouterInputs[T][K], // mutation 的输入参数
|
||||
unknown // mutation 的上下文类型
|
||||
>;
|
||||
|
||||
/**
|
||||
* 自定义 Hook:用于处理实体的 mutation 操作,并内置缓存失效机制。
|
||||
* @template T - 实体类型的键名(如 'post', 'user')
|
||||
* @param {T} key - 实体键名
|
||||
* @param {EntityOptions<T>} [options] - 可选的 mutation 回调函数配置
|
||||
* @returns 返回一个包含多个 mutation 函数的对象
|
||||
* @description 该 Hook 封装了常见的 mutation 操作(如 create, update, deleteMany 等),并在每次 mutation 成功后自动失效相关缓存。
|
||||
*/
|
||||
export function useEntity<T extends keyof RouterInputs>(
|
||||
key: T,
|
||||
options?: EntityOptions<T>
|
||||
) {
|
||||
const trpc = useTRPC();
|
||||
const queryClient = useQueryClient();
|
||||
/**
|
||||
* 创建 mutation 处理函数。
|
||||
* @template K - mutation 方法名
|
||||
* @param {K} mutation - mutation 方法名
|
||||
* @returns 返回一个配置好的 mutation 函数
|
||||
* @description 该函数根据传入的 mutation 方法名,生成对应的 mutation 函数,并配置 onSuccess 回调。
|
||||
*/
|
||||
|
||||
const createMutationHandler = <K extends MutationType<T>>(mutation: K) => {
|
||||
// 获取对应的 tRPC mutation 配置
|
||||
const mutationOptions = trpc[key as keyof typeof trpc][mutation as any].mutationOptions();
|
||||
|
||||
// 使用 TanStack Query 的 useMutation 创建 mutation
|
||||
return useMutation({
|
||||
...mutationOptions,
|
||||
onSuccess: (data, variables, context) => {
|
||||
// 调用原始配置的 onSuccess 回调(如果有)
|
||||
mutationOptions.onSuccess?.(data as any, variables as any, context);
|
||||
|
||||
// 失效指定实体的缓存
|
||||
queryClient.invalidateQueries({ queryKey: [key] });
|
||||
|
||||
// 调用用户自定义的 onSuccess 回调
|
||||
options?.[mutation]?.onSuccess?.(data as any, variables as any, context);
|
||||
},
|
||||
}) as MutationResult<T, K>;
|
||||
};
|
||||
|
||||
// 返回包含多个 mutation 函数的对象
|
||||
return {
|
||||
create: createMutationHandler("create"),
|
||||
createCourse: createMutationHandler("createCourse"),
|
||||
update: createMutationHandler("update"),
|
||||
deleteMany: createMutationHandler("deleteMany"),
|
||||
softDeleteByIds: createMutationHandler("softDeleteByIds"),
|
||||
restoreByIds: createMutationHandler("restoreByIds"),
|
||||
updateOrder: createMutationHandler("updateOrder"),
|
||||
updateOrderByIds: createMutationHandler("updateOrderByIds"),
|
||||
};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./utils"
|
||||
export * from "./hooks"
|
||||
export * from "./trpc"
|
|
@ -0,0 +1,8 @@
|
|||
import { AppRouter } from "@repo/backend/trpc"
|
||||
import { inferReactQueryProcedureOptions } from "@trpc/react-query";
|
||||
import { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
|
||||
import { createTRPCContext } from '@trpc/tanstack-react-query';
|
||||
export type ReactQueryOptions = inferReactQueryProcedureOptions<AppRouter>;
|
||||
export type RouterInputs = inferRouterInputs<AppRouter>;
|
||||
export type RouterOutputs = inferRouterOutputs<AppRouter>;
|
||||
export const { TRPCProvider, useTRPC, useTRPCClient } = createTRPCContext<AppRouter>();
|
|
@ -0,0 +1,62 @@
|
|||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { getQueryKey } from "@trpc/react-query";
|
||||
|
||||
/**
|
||||
* 根据查询客户端缓存生成唯一数据列表的函数。
|
||||
*
|
||||
* @template T - 数据类型
|
||||
* @param {QueryClient} client - 查询客户端实例
|
||||
* @param {any} trpcQueryKey - 用于获取查询键的参数
|
||||
* @param {string} uniqueField - 唯一字段的名称,默认为 'id'
|
||||
* @returns {T[]} - 返回唯一的数据列表
|
||||
*/
|
||||
export function getCacheDataFromQuery<T extends Record<string, any>>(client: QueryClient, trpcQueryKey: any, uniqueField: string = 'id'): T[] {
|
||||
// 获取查询缓存数据
|
||||
const cacheData = client.getQueriesData({ queryKey: getQueryKey(trpcQueryKey) });
|
||||
// 提取并整理缓存数据
|
||||
const data = cacheData
|
||||
.flatMap(cache => cache.slice(1))
|
||||
.flat()
|
||||
.filter(item => item !== undefined) as T[];
|
||||
// console.log('cacheData', cacheData)
|
||||
// console.log('data', data)
|
||||
// 使用 Map 进行去重
|
||||
const uniqueDataMap = new Map<string | number, T>();
|
||||
data.forEach((item: T) => {
|
||||
if (item && item[uniqueField] !== undefined) {
|
||||
uniqueDataMap.set(item[uniqueField], item);
|
||||
}
|
||||
});
|
||||
|
||||
// 转换为数组返回唯一的数据列表
|
||||
return Array.from(uniqueDataMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找唯一数据列表中的匹配对象。
|
||||
*
|
||||
* @template T - 数据类型
|
||||
* @param {T[]} uniqueData - 唯一数据列表
|
||||
* @param {string} key - 唯一字段的键值
|
||||
* @param {string} uniqueField - 唯一字段的名称,默认为 'id'
|
||||
* @returns {T | undefined} - 返回匹配的对象,如果没有找到则返回 undefined
|
||||
*/
|
||||
export function findDataByKey<T extends Record<string, any>>(uniqueData: T[], key: string | number, uniqueField: string = 'id'): T | undefined {
|
||||
return uniqueData.find(item => item[uniqueField] === key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 综合使用生成唯一数据和查找数据的功能。
|
||||
*
|
||||
* @template T - 数据类型
|
||||
* @param {QueryClient} client - 查询客户端实例
|
||||
* @param {any} trpcQueryKey - 用于获取查询键的参数
|
||||
* @param {string} key - 唯一字段的键值
|
||||
* @param {string} uniqueField - 唯一字段的名称,默认为 'id'
|
||||
* @returns {T | undefined} - 返回匹配的对象,如果没有找到则返回 undefined
|
||||
*/
|
||||
export function findQueryData<T extends Record<string, any>>(client: QueryClient, trpcQueryKey: any, key: string | number, uniqueField: string = 'id'): T | undefined {
|
||||
const uniqueData = getCacheDataFromQuery<T>(client, trpcQueryKey, uniqueField);
|
||||
return findDataByKey<T>(uniqueData, key, uniqueField);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from "./api"
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"extends": "@repo/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"module": "es2022",
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["dom", "es2022"],
|
||||
"jsx": "react-jsx",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"incremental": true,
|
||||
"strict": true,
|
||||
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
|
||||
"useDefineForClassFields": false,
|
||||
"paths": {
|
||||
"@repo/backend/*": ["../../apps/backend/src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
DATABASE_URL="postgresql://root:Letusdoit000@localhost:5432/app?schema=public"
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "@repo/db",
|
||||
"version": "1.0.0",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"db:migrate": "prisma migrate dev --skip-generate",
|
||||
"db:deploy": "prisma migrate deploy",
|
||||
"db:generate": "prisma generate",
|
||||
"db:push": "prisma db push",
|
||||
"db:seed": "tsx src/seed.ts",
|
||||
"format": "prisma format",
|
||||
"studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.3.1",
|
||||
"concurrently": "^8.0.0",
|
||||
"prisma": "^6.6.0",
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsup": "^8.3.5",
|
||||
"tsx": "^4.19.4",
|
||||
"typescript": "^5.5.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"password" TEXT,
|
||||
"salt" TEXT,
|
||||
"phone" TEXT,
|
||||
"email" TEXT NOT NULL,
|
||||
"avatar" TEXT,
|
||||
"is_system" BOOLEAN,
|
||||
"is_admin" BOOLEAN,
|
||||
"last_sign_time" TIMESTAMP(3),
|
||||
"deactivated_time" TIMESTAMP(3),
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_time" TIMESTAMP(3),
|
||||
"last_modified_time" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "attachments" (
|
||||
"id" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"hash" TEXT NOT NULL,
|
||||
"size" INTEGER NOT NULL,
|
||||
"mimetype" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"width" INTEGER,
|
||||
"height" INTEGER,
|
||||
"deleted_time" TIMESTAMP(3),
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by" TEXT NOT NULL,
|
||||
"last_modified_by" TEXT,
|
||||
"thumbnail_path" TEXT,
|
||||
|
||||
CONSTRAINT "attachments_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "notification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"from_user_id" TEXT NOT NULL,
|
||||
"to_user_id" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"url_path" TEXT,
|
||||
"is_read" BOOLEAN NOT NULL DEFAULT false,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "notification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "setting" (
|
||||
"instance_id" TEXT NOT NULL,
|
||||
"disallow_sign_up" BOOLEAN,
|
||||
"disallow_space_creation" BOOLEAN,
|
||||
"disallow_space_invitation" BOOLEAN,
|
||||
"enable_email_verification" BOOLEAN,
|
||||
"ai_config" TEXT,
|
||||
"brand_name" TEXT,
|
||||
"brand_logo" TEXT,
|
||||
|
||||
CONSTRAINT "setting_pkey" PRIMARY KEY ("instance_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "trash" (
|
||||
"id" TEXT NOT NULL,
|
||||
"resource_type" TEXT NOT NULL,
|
||||
"resource_id" TEXT NOT NULL,
|
||||
"parent_id" TEXT,
|
||||
"deleted_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted_by" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "trash_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_last_visit" (
|
||||
"id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"resource_type" TEXT NOT NULL,
|
||||
"resource_id" TEXT NOT NULL,
|
||||
"parent_resource_id" TEXT NOT NULL,
|
||||
"last_visit_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "user_last_visit_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_clients" (
|
||||
"id" TEXT NOT NULL,
|
||||
"client_id" TEXT NOT NULL,
|
||||
"client_secret" TEXT,
|
||||
"client_name" TEXT NOT NULL,
|
||||
"client_uri" TEXT,
|
||||
"logo_uri" TEXT,
|
||||
"contacts" TEXT[],
|
||||
"redirect_uris" TEXT[],
|
||||
"post_logout_redirect_uris" TEXT[],
|
||||
"token_endpoint_auth_method" TEXT NOT NULL,
|
||||
"grant_types" TEXT[],
|
||||
"response_types" TEXT[],
|
||||
"scope" TEXT NOT NULL,
|
||||
"jwks_uri" TEXT,
|
||||
"jwks" TEXT,
|
||||
"policy_uri" TEXT,
|
||||
"tos_uri" TEXT,
|
||||
"require_pkce" BOOLEAN NOT NULL DEFAULT false,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"created_by" TEXT,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"last_modified_time" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "oidc_clients_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_consents" (
|
||||
"id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"client_id" TEXT NOT NULL,
|
||||
"scope" TEXT NOT NULL,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expires_at" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "oidc_consents_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_authorization_codes" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"client_id" TEXT NOT NULL,
|
||||
"scope" TEXT NOT NULL,
|
||||
"redirect_uri" TEXT NOT NULL,
|
||||
"code_challenge" TEXT,
|
||||
"code_challenge_method" TEXT,
|
||||
"nonce" TEXT,
|
||||
"auth_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expires_at" TIMESTAMP(3) NOT NULL,
|
||||
"used" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "oidc_authorization_codes_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_tokens" (
|
||||
"id" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"client_id" TEXT NOT NULL,
|
||||
"token_type" TEXT NOT NULL,
|
||||
"scope" TEXT NOT NULL,
|
||||
"expires_at" TIMESTAMP(3) NOT NULL,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"is_revoked" BOOLEAN NOT NULL DEFAULT false,
|
||||
"parent_id" TEXT,
|
||||
|
||||
CONSTRAINT "oidc_tokens_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_sessions" (
|
||||
"id" TEXT NOT NULL,
|
||||
"session_id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"expires_at" TIMESTAMP(3) NOT NULL,
|
||||
"last_active" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"device_info" TEXT,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"last_modified_time" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "oidc_sessions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "oidc_key_pairs" (
|
||||
"id" TEXT NOT NULL,
|
||||
"kid" TEXT NOT NULL,
|
||||
"private_key" TEXT NOT NULL,
|
||||
"public_key" TEXT NOT NULL,
|
||||
"algorithm" TEXT NOT NULL,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"created_time" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expires_at" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "oidc_key_pairs_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_phone_key" ON "users"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "attachments_token_key" ON "attachments"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "notification_to_user_id_is_read_created_time_idx" ON "notification"("to_user_id", "is_read", "created_time");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "trash_resource_type_resource_id_key" ON "trash"("resource_type", "resource_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_last_visit_user_id_resource_type_idx" ON "user_last_visit"("user_id", "resource_type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "user_last_visit_user_id_resource_type_parent_resource_id_key" ON "user_last_visit"("user_id", "resource_type", "parent_resource_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_clients_client_id_key" ON "oidc_clients"("client_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_consents_user_id_client_id_key" ON "oidc_consents"("user_id", "client_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_authorization_codes_code_key" ON "oidc_authorization_codes"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_tokens_token_key" ON "oidc_tokens"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "oidc_tokens_user_id_token_type_is_revoked_idx" ON "oidc_tokens"("user_id", "token_type", "is_revoked");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_sessions_session_id_key" ON "oidc_sessions"("session_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "oidc_key_pairs_kid_key" ON "oidc_key_pairs"("kid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "oidc_consents" ADD CONSTRAINT "oidc_consents_client_id_fkey" FOREIGN KEY ("client_id") REFERENCES "oidc_clients"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "oidc_authorization_codes" ADD CONSTRAINT "oidc_authorization_codes_client_id_fkey" FOREIGN KEY ("client_id") REFERENCES "oidc_clients"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "oidc_tokens" ADD CONSTRAINT "oidc_tokens_client_id_fkey" FOREIGN KEY ("client_id") REFERENCES "oidc_clients"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -0,0 +1,3 @@
|
|||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
|
@ -0,0 +1,218 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
||||
output = "../generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgres"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
password String?
|
||||
salt String?
|
||||
phone String? @unique
|
||||
email String @unique
|
||||
avatar String?
|
||||
isSystem Boolean? @map("is_system")
|
||||
isAdmin Boolean? @map("is_admin")
|
||||
lastSignTime DateTime? @map("last_sign_time")
|
||||
deactivatedTime DateTime? @map("deactivated_time")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
deletedTime DateTime? @map("deleted_time")
|
||||
lastModifiedTime DateTime? @updatedAt @map("last_modified_time")
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model Attachments {
|
||||
id String @id @default(cuid())
|
||||
token String @unique
|
||||
hash String
|
||||
size Int
|
||||
mimetype String
|
||||
path String
|
||||
width Int?
|
||||
height Int?
|
||||
deletedTime DateTime? @map("deleted_time")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
createdBy String @map("created_by")
|
||||
lastModifiedBy String? @map("last_modified_by")
|
||||
thumbnailPath String? @map("thumbnail_path")
|
||||
|
||||
@@map("attachments")
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
fromUserId String @map("from_user_id")
|
||||
toUserId String @map("to_user_id")
|
||||
type String @map("type")
|
||||
message String @map("message")
|
||||
urlPath String? @map("url_path")
|
||||
isRead Boolean @default(false) @map("is_read")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
createdBy String @map("created_by")
|
||||
|
||||
@@index([toUserId, isRead, createdTime])
|
||||
@@map("notification")
|
||||
}
|
||||
|
||||
model Setting {
|
||||
instanceId String @id @default(cuid()) @map("instance_id")
|
||||
disallowSignUp Boolean? @map("disallow_sign_up")
|
||||
disallowSpaceCreation Boolean? @map("disallow_space_creation")
|
||||
disallowSpaceInvitation Boolean? @map("disallow_space_invitation")
|
||||
enableEmailVerification Boolean? @map("enable_email_verification")
|
||||
aiConfig String? @map("ai_config")
|
||||
brandName String? @map("brand_name")
|
||||
brandLogo String? @map("brand_logo")
|
||||
|
||||
@@map("setting")
|
||||
}
|
||||
|
||||
model Trash {
|
||||
id String @id @default(cuid())
|
||||
resourceType String @map("resource_type")
|
||||
resourceId String @map("resource_id")
|
||||
parentId String? @map("parent_id")
|
||||
deletedTime DateTime @default(now()) @map("deleted_time")
|
||||
deletedBy String @map("deleted_by")
|
||||
|
||||
@@unique([resourceType, resourceId])
|
||||
@@map("trash")
|
||||
}
|
||||
|
||||
model UserLastVisit {
|
||||
id String @id @default(cuid())
|
||||
userId String @map("user_id")
|
||||
resourceType String @map("resource_type")
|
||||
resourceId String @map("resource_id")
|
||||
parentResourceId String @map("parent_resource_id")
|
||||
lastVisitTime DateTime @default(now()) @map("last_visit_time")
|
||||
|
||||
@@unique([userId, resourceType, parentResourceId])
|
||||
@@index([userId, resourceType])
|
||||
@@map("user_last_visit")
|
||||
}
|
||||
|
||||
// OIDC 客户端相关模型
|
||||
model OidcClient {
|
||||
id String @id @default(cuid())
|
||||
clientId String @unique @map("client_id")
|
||||
clientSecret String? @map("client_secret")
|
||||
clientName String @map("client_name")
|
||||
clientUri String? @map("client_uri")
|
||||
logoUri String? @map("logo_uri")
|
||||
contacts String[]
|
||||
redirectUris String[] @map("redirect_uris")
|
||||
postLogoutRedirectUris String[] @map("post_logout_redirect_uris")
|
||||
tokenEndpointAuthMethod String @map("token_endpoint_auth_method")
|
||||
grantTypes String[] @map("grant_types")
|
||||
responseTypes String[] @map("response_types")
|
||||
scope String
|
||||
jwksUri String? @map("jwks_uri")
|
||||
jwks String?
|
||||
policyUri String? @map("policy_uri")
|
||||
tosUri String? @map("tos_uri")
|
||||
requirePkce Boolean @default(false) @map("require_pkce")
|
||||
active Boolean @default(true)
|
||||
createdBy String? @map("created_by")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
lastModifiedTime DateTime? @updatedAt @map("last_modified_time")
|
||||
|
||||
// 关联模型
|
||||
consents OidcConsent[]
|
||||
authorizationCodes OidcCode[]
|
||||
tokens OidcToken[]
|
||||
|
||||
@@map("oidc_clients")
|
||||
}
|
||||
|
||||
// 用户同意记录
|
||||
model OidcConsent {
|
||||
id String @id @default(cuid())
|
||||
userId String @map("user_id")
|
||||
clientId String @map("client_id")
|
||||
scope String
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
expiresAt DateTime? @map("expires_at")
|
||||
|
||||
// 关联
|
||||
client OidcClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, clientId])
|
||||
@@map("oidc_consents")
|
||||
}
|
||||
|
||||
// 授权码
|
||||
model OidcCode {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
userId String @map("user_id")
|
||||
clientId String @map("client_id")
|
||||
scope String
|
||||
redirectUri String @map("redirect_uri")
|
||||
codeChallenge String? @map("code_challenge")
|
||||
codeChallengeMethod String? @map("code_challenge_method")
|
||||
nonce String?
|
||||
authTime DateTime @default(now()) @map("auth_time")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
used Boolean @default(false)
|
||||
|
||||
// 关联
|
||||
client OidcClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("oidc_authorization_codes")
|
||||
}
|
||||
|
||||
// 统一令牌表(合并access和refresh token)
|
||||
model OidcToken {
|
||||
id String @id @default(cuid())
|
||||
token String @unique
|
||||
userId String @map("user_id")
|
||||
clientId String @map("client_id")
|
||||
tokenType String @map("token_type") // "access" 或 "refresh"
|
||||
scope String
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
isRevoked Boolean @default(false) @map("is_revoked")
|
||||
parentId String? @map("parent_id") // 用于关联refresh token和对应的access token
|
||||
|
||||
// 关联
|
||||
client OidcClient @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId, tokenType, isRevoked])
|
||||
@@map("oidc_tokens")
|
||||
}
|
||||
|
||||
// Session管理
|
||||
model OidcSession {
|
||||
id String @id @default(cuid())
|
||||
sessionId String @unique @map("session_id")
|
||||
userId String @map("user_id")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
lastActive DateTime @default(now()) @map("last_active")
|
||||
deviceInfo String? @map("device_info")
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
lastModifiedTime DateTime? @updatedAt @map("last_modified_time")
|
||||
|
||||
@@map("oidc_sessions")
|
||||
}
|
||||
|
||||
// 供应商的密钥对
|
||||
model OidcKeyPair {
|
||||
id String @id @default(cuid())
|
||||
kid String @unique
|
||||
privateKey String @map("private_key")
|
||||
publicKey String @map("public_key")
|
||||
algorithm String
|
||||
active Boolean @default(true)
|
||||
createdTime DateTime @default(now()) @map("created_time")
|
||||
expiresAt DateTime? @map("expires_at")
|
||||
|
||||
@@map("oidc_key_pairs")
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { PrismaClient } from "../generated/prisma";
|
||||
|
||||
const globalForPrisma = global as unknown as { prisma: PrismaClient };
|
||||
|
||||
export const prisma =
|
||||
globalForPrisma.prisma || new PrismaClient();
|
||||
|
||||
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./client"
|
||||
export * from "../generated/prisma" // exports generated types from prisma
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"module": "esnext",
|
||||
"lib": [
|
||||
"DOM",
|
||||
"es2022"
|
||||
],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"removeComments": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitReturns": false,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"noImplicitOverride": false,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "dist",
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/__tests__"
|
||||
]
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
# `@workspace/eslint-config`
|
||||
# `@repo/eslint-config`
|
||||
|
||||
Shared eslint configuration for the workspace.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@workspace/eslint-config",
|
||||
"name": "@repo/eslint-config",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# build
|
||||
/dist
|
||||
/build
|
||||
/storybook-static
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
.env
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/icons.iml" filepath="$PROJECT_DIR$/.idea/icons.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023-2025 Teable, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "@repo/icons",
|
||||
"version": "1.7.0",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/teableio/teable",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/teableio/teable",
|
||||
"directory": "packages/icons"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "rimraf ./dist ./build ./tsconfig.tsbuildinfo ./node_modules/.cache",
|
||||
"dev": "rm -rf dist && tsc --watch",
|
||||
"test": "echo \"Error: no test specified\"",
|
||||
"lint": "eslint . --ext .ts,.tsx,.js,.jsx,.cjs,.mjs,.mdx --cache --cache-location ../../.cache/eslint/icons.eslintcache",
|
||||
"typecheck": "tsc --project ./tsconfig.json --noEmit",
|
||||
"generate": "rm -rf src/components && node ./scripts/generate.mjs"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/core": "8.1.0",
|
||||
"@svgr/plugin-jsx": "8.1.0",
|
||||
"@svgr/plugin-prettier": "8.1.0",
|
||||
"@svgr/plugin-svgo": "8.1.0",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/node": "20.9.0",
|
||||
"@types/react": "18.2.45",
|
||||
"axios": "1.7.7",
|
||||
"chalk": "5.3.0",
|
||||
"dotenv": "16.4.5",
|
||||
"eslint": "8.57.0",
|
||||
"figma-js": "1.16.0",
|
||||
"fs-extra": "11.2.0",
|
||||
"lodash": "4.17.21",
|
||||
"rimraf": "5.0.5",
|
||||
"typescript": "5.4.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
import path from 'path';
|
||||
import { transform } from '@svgr/core';
|
||||
import axios from 'axios';
|
||||
import chalk from 'chalk';
|
||||
import dotenv from 'dotenv';
|
||||
import fs from 'fs-extra';
|
||||
import _ from 'lodash';
|
||||
import * as Figma from 'figma-js';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const componentsDir = 'src/components';
|
||||
|
||||
// Add .env file
|
||||
const FIGMA_API_TOKEN = process.env.FIGMA_API_TOKEN;
|
||||
const FIGMA_FILE_ID = process.env.FIGMA_FILE_ID;
|
||||
const FIGMA_CANVAS = process.env.FIGMA_CANVAS;
|
||||
|
||||
if (!FIGMA_API_TOKEN) {
|
||||
throw new Error('Missing environment variable FIGMA_API_TOKEN');
|
||||
}
|
||||
|
||||
if (!FIGMA_FILE_ID) {
|
||||
throw new Error('Missing environment variable FIGMA_FILE_ID');
|
||||
}
|
||||
|
||||
if (!FIGMA_CANVAS) {
|
||||
throw new Error('Missing environment variable FIGMA_CANVAS');
|
||||
}
|
||||
|
||||
const figmaApi = Figma.Client({ personalAccessToken: FIGMA_API_TOKEN });
|
||||
|
||||
const getSvgs = async ({ fileId, canvas, group }) => {
|
||||
const file = await figmaApi.file(fileId);
|
||||
const { document } = file.data;
|
||||
const iconsNode = document.children.find(({ name }) => name === canvas);
|
||||
if (!iconsNode) {
|
||||
throw new Error(`Couldn't find page with name ${canvas}`);
|
||||
}
|
||||
const usingIconNodes = iconsNode.children.find(({ name }) => name === group)?.children || [];
|
||||
const usingNodeId = usingIconNodes.map(({ id }) => id);
|
||||
const svgs = await figmaApi.fileImages(fileId, {
|
||||
format: 'svg',
|
||||
ids: usingNodeId,
|
||||
});
|
||||
return usingIconNodes.map(({ id, name }) => ({ id, name, url: svgs.data.images[id] }));
|
||||
};
|
||||
|
||||
const downloadSVGsData = async (data, batchSize = 20, delayBetweenBatches = 500) => {
|
||||
const results = [];
|
||||
const batchCount = Math.ceil(data.length / batchSize);
|
||||
|
||||
for (let i = 0; i < batchCount; i++) {
|
||||
const batchData = data.slice(i * batchSize, (i + 1) * batchSize);
|
||||
|
||||
console.log(`Processing batch ${i + 1}/${batchCount}, containing ${batchData.length} requests`);
|
||||
|
||||
const batchResults = await Promise.all(
|
||||
batchData.map(async (dataItem) => {
|
||||
try {
|
||||
const downloadedSvg = await axios.get(dataItem.url);
|
||||
return {
|
||||
...dataItem,
|
||||
data: downloadedSvg.data,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to download ${dataItem.url}:`, error.message);
|
||||
return {
|
||||
...dataItem,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
results.push(...batchResults);
|
||||
|
||||
if (i < batchCount - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delayBetweenBatches));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
const transformReactComponent = (svgList) => {
|
||||
if (!fs.existsSync(componentsDir)) {
|
||||
fs.mkdirSync(componentsDir);
|
||||
}
|
||||
svgList.forEach((svg) => {
|
||||
if (!svg.success) return;
|
||||
const svgCode = svg.data;
|
||||
const svgName = svg.name.split('/').pop();
|
||||
const camelCaseInput = _.camelCase(svgName);
|
||||
const componentName = camelCaseInput.charAt(0).toUpperCase() + camelCaseInput.slice(1);
|
||||
const componentFileName = `${componentName}.tsx`;
|
||||
|
||||
// Converts SVG code into React code using SVGR library
|
||||
const componentCode = transform.sync(
|
||||
svgCode,
|
||||
{
|
||||
typescript: true,
|
||||
icon: true,
|
||||
replaceAttrValues: {
|
||||
'#000': 'currentColor',
|
||||
},
|
||||
plugins: [
|
||||
// Clean SVG files using SVGO
|
||||
'@svgr/plugin-svgo',
|
||||
// Generate JSX
|
||||
'@svgr/plugin-jsx',
|
||||
// Format the result using Prettier
|
||||
'@svgr/plugin-prettier',
|
||||
],
|
||||
},
|
||||
{ componentName }
|
||||
);
|
||||
// 6. Write generated component to file system
|
||||
fs.outputFileSync(path.resolve(componentsDir, componentFileName), componentCode);
|
||||
// fs.outputFileSync(path.resolve('src/icons', `${svgName}.svg`), svg.data);
|
||||
});
|
||||
};
|
||||
|
||||
const genIndexContent = () => {
|
||||
let indexContent = '';
|
||||
const indexPath = path.resolve('src/index.ts');
|
||||
|
||||
fs.readdirSync(componentsDir).forEach((componentFileName) => {
|
||||
// Convert name to pascal case
|
||||
const componentName = componentFileName.split('.')[0];
|
||||
|
||||
// Export statement
|
||||
const componentExport = `export { default as ${componentName} } from './components/${componentName}';\n`;
|
||||
|
||||
indexContent += componentExport;
|
||||
});
|
||||
|
||||
// Write the content to file system
|
||||
fs.writeFileSync(indexPath, indexContent);
|
||||
};
|
||||
|
||||
const generate = async () => {
|
||||
console.log(chalk.magentaBright('-> Fetching icons metadata'));
|
||||
const svgs = await getSvgs({ fileId: FIGMA_FILE_ID, canvas: FIGMA_CANVAS, group: 'using' });
|
||||
console.log(chalk.blueBright('-> Downloading SVG code'));
|
||||
const svgsData = await downloadSVGsData(svgs);
|
||||
console.log(chalk.cyanBright('-> Converting to React components'));
|
||||
transformReactComponent(svgsData);
|
||||
console.log(chalk.yellowBright('-> Writing exports components'));
|
||||
genIndexContent();
|
||||
console.log(chalk.greenBright('-> All done! ✅'));
|
||||
};
|
||||
|
||||
generate();
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const A = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M21 21 12 3 3 21m3-7h12"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default A;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Admin = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22.429 18.357c-.077.41-.342.676-.673.676H21.7a1.18 1.18 0 0 0-1.176 1.176c.009.154.044.306.103.448a.85.85 0 0 1-.29 1.026l-.032.022-1.364.751a.9.9 0 0 1-.374.086.91.91 0 0 1-.67-.287c-.176-.19-.642-.584-.97-.584-.32 0-.793.394-.959.574a.92.92 0 0 1-1.012.21l-1.35-.75c-.355-.247-.479-.69-.317-1.05.028-.066.103-.277.103-.444a1.18 1.18 0 0 0-1.178-1.176h-.046c-.34 0-.603-.267-.682-.678a7 7 0 0 1-.116-1.09c0-.46.104-1.031.116-1.092.08-.41.343-.678.674-.678h.055c.649 0 1.176-.525 1.177-1.173a1.3 1.3 0 0 0-.104-.45.85.85 0 0 1 .29-1.027l.033-.02 1.4-.769.026-.01a.93.93 0 0 1 1.003.21c.17.178.629.55.946.55.312 0 .768-.364.938-.542a.93.93 0 0 1 1.006-.2l1.374.76c.357.246.482.69.32 1.05a1.4 1.4 0 0 0-.102.446 1.177 1.177 0 0 0 1.176 1.174h.047c.338 0 .603.266.681.678.012.062.116.632.116 1.092 0 .483-.116 1.086-.114 1.09m-1.024-1.812a2.244 2.244 0 0 1-1.953-2.224q.007-.349.12-.68l-.972-.54q-.19.175-.401.325-.638.449-1.212.45-.582 0-1.224-.458a3.5 3.5 0 0 1-.402-.334l-1.017.56c.057.168.12.417.12.678a2.25 2.25 0 0 1-1.953 2.225 5 5 0 0 0-.067.719q.009.36.067.717a2.24 2.24 0 0 1 1.954 2.225c0 .26-.067.51-.122.68l.94.525q.192-.182.403-.34c.431-.314.85-.476 1.242-.476.396 0 .819.165 1.254.487q.214.16.405.346l.985-.542a2.2 2.2 0 0 1-.12-.679 2.24 2.24 0 0 1 1.953-2.225 5.5 5.5 0 0 0 .067-.72c0-.234-.04-.532-.067-.72m-4.47 2.788a2.08 2.08 0 0 1-2.078-2.076 2.078 2.078 0 0 1 4.154 0 2.08 2.08 0 0 1-2.077 2.076m0-3.041c-.54 0-.985.426-1.008.966a1.007 1.007 0 0 0 2.014 0 1.01 1.01 0 0 0-1.007-.966m-3.014-5.288-.339.263c-.688.612-2.002.817-2.87.884l-.112-.003q-.366.002-.731.035h-.01v.002c-3.929.37-7.014 3.663-7.014 7.662v1.176h8.61c.227.488.508.95.84 1.373H2.151a.69.69 0 0 1-.694-.686v-1.863c0-3.729 2.26-7.035 5.762-8.424l.397-.156-.337-.263a5.3 5.3 0 0 1-2.068-4.203c0-2.947 2.417-5.344 5.388-5.344s5.388 2.397 5.39 5.344a5.31 5.31 0 0 1-2.068 4.203m-3.322-8.173c-2.205 0-3.999 1.782-3.999 3.97 0 2.19 1.794 3.972 4 3.972s4-1.781 4-3.972-1.795-3.97-4-3.97"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Admin;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const AlertCircle = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10M12 8v4M12 16h.01"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default AlertCircle;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const AlertTriangle = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4M12 17h.01"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default AlertTriangle;
|
|
@ -0,0 +1,26 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Anthropic = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<path fill="#CA9F7B" d="M6 0h12q6 0 6 6v12q0 6-6 6H6q-6 0-6-6V6q0-6 6-6" />
|
||||
<path
|
||||
fill="#191918"
|
||||
d="M15.384 6.435H12.97l4.405 11.13h2.416zm-6.979 0L4 17.565h2.463l.901-2.337h4.609l.9 2.337h2.464l-4.405-11.13zm-.244 6.726 1.508-3.912 1.507 3.912z"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default Anthropic;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Apple = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 20.94c1.5 0 2.75 1.06 4 1.06 3 0 6-8 6-12.22A4.91 4.91 0 0 0 17 5c-2.22 0-4 1.44-5 2-1-.56-2.78-2-5-2a4.9 4.9 0 0 0-5 4.78C2 14 5 22 8 22c1.25 0 2.5-1.06 4-1.06"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M10 2c1 .5 2 2 2 5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Apple;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Array = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M8.949 22.348v-1.704H6.765V3.41h2.184V1.707H4.82v20.64zm10.008 0V1.707h-4.128V3.41h2.184v17.232h-2.184v1.704z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Array;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowDown = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 5v14M19 12l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowDown;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowLeft = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M19 12H5M12 19l-7-7 7-7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowLeft;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowRight = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 12h14M12 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowRight;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowUp = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 19V5M5 12l7-7 7 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowUp;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowUpDown = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m11 17-4 4-4-4M7 21V9M21 7l-4-4-4 4M17 15V3"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowUpDown;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ArrowUpRight = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 17 17 7M7 7h10v10"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ArrowUpRight;
|
|
@ -0,0 +1,22 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Audio = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.734 10.64a.19.19 0 0 0-.187-.187H18.14a.19.19 0 0 0-.188.188 5.953 5.953 0 1 1-11.906 0 .19.19 0 0 0-.188-.188H4.453a.19.19 0 0 0-.187.188 7.735 7.735 0 0 0 6.797 7.678v2.4H7.656c-.321 0-.579.335-.579.75v.843c0 .104.066.188.145.188h9.554c.08 0 .145-.084.145-.187v-.844c0-.415-.258-.75-.579-.75h-3.5V18.33a7.74 7.74 0 0 0 6.891-7.69"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 14.625c2.2 0 3.984-1.762 3.984-3.937v-5.25C15.984 3.263 14.201 1.5 12 1.5S8.016 3.263 8.016 5.438v5.25c0 2.175 1.783 3.937 3.984 3.937M9.797 5.438c0-1.186.982-2.157 2.203-2.157s2.203.97 2.203 2.157v5.25c0 1.185-.982 2.156-2.203 2.156s-2.203-.97-2.203-2.156z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Audio;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Azure = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="#1E88E5"
|
||||
d="M13.26 2.69 5.472 19.262 0 19.2 6.108 8.688l7.152-6.002m.84 1.308L24 21.31H5.69l11.16-1.988-5.844-6.952z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Azure;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const BarChart2 = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M18 20V10M12 20V4M6 20v-6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default BarChart2;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Bell = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M18 8A6 6 0 1 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Bell;
|
|
@ -0,0 +1,25 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Boolean = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16 4a8 8 0 0 1 0 16H8A8 8 0 0 1 8 4zm0 2H8a6 6 0 0 0-.225 11.996L8 18h8a6 6 0 0 0 .225-11.996zm0 1a5 5 0 1 1 0 10 5 5 0 0 1 0-10"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default Boolean;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Building2 = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M6 22V4c0-.27 0-.55.07-.82a1.48 1.48 0 0 1 1.1-1.11C7.46 2 8.73 2 9 2h7c.27 0 .55 0 .82.07a1.48 1.48 0 0 1 1.11 1.1c.07.28.07.56.07.83v18zM2 14v6c0 1.1.9 2 2 2h2V12H4c-.27 0-.55 0-.82.07s-.52.2-.72.4c-.19.19-.32.44-.39.71A3.4 3.4 0 0 0 2 14M20.82 9.07A3.4 3.4 0 0 0 20 9h-2v13h2a2 2 0 0 0 2-2v-9c0-.28 0-.55-.07-.82s-.2-.52-.4-.72c-.19-.19-.44-.32-.71-.39M10 6h4M10 10h4M10 14h4M10 18h4"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Building2;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Calendar = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M16 2v4M8 2v4m-5 4h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Calendar;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Check = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M20 6 9 17l-5-5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Check;
|
|
@ -0,0 +1,29 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const CheckCircle2 = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m9 12 2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default CheckCircle2;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const CheckSquare = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m9 11 3 3L22 4m-1 8v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default CheckSquare;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Checked = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 16 16"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.667 2H3.333C2.593 2 2 2.6 2 3.333v9.334C2 13.4 2.593 14 3.333 14h9.334c.74 0 1.333-.6 1.333-1.333V3.333C14 2.6 13.407 2 12.667 2m-6 9.333L3.333 8l.94-.94 2.394 2.387 5.06-5.06.94.946z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Checked;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronDown = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m6 9 6 6 6-6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronDown;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronLeft = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m15 18-6-6 6-6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronLeft;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronRight = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m9 18 6-6-6-6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronRight;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronUp = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m18 15-6-6-6 6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronUp;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronsLeft = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m11 17-5-5 5-5M18 17l-5-5 5-5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronsLeft;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronsRight = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m13 17 5-5-5-5M6 17l5-5-5-5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronsRight;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ChevronsUpDown = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m7 15 5 5 5-5M7 9l5-5 5 5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ChevronsUpDown;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Circle = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Circle;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const ClipboardList = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 2H9a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2M12 11h4M12 16h4M8 11h.01M8 16h.01"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default ClipboardList;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Clock4 = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 6v6l4 2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Clock4;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Code = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m16 18 6-6-6-6M8 6l-6 6 6 6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Code;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Code2 = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="m18 16 4-4-4-4M6 8l-4 4 4 4M14.5 4l-5 16"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Code2;
|
|
@ -0,0 +1,33 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Cohere = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<path
|
||||
fill="#39594D"
|
||||
d="M7.775 14.288c.645 0 1.931-.036 3.705-.767 2.07-.852 6.188-2.4 9.158-3.988 2.078-1.11 2.987-2.581 2.987-4.56A4.97 4.97 0 0 0 18.653 0H7.144A7.144 7.144 0 0 0 0 7.144c0 3.944 2.994 7.144 7.775 7.144"
|
||||
/>
|
||||
<path
|
||||
fill="#D18EE2"
|
||||
d="M9.72 19.207a4.785 4.785 0 0 1 2.95-4.42l3.626-1.504c3.666-1.52 7.702 1.173 7.702 5.143a5.566 5.566 0 0 1-5.57 5.567h-3.924a4.784 4.784 0 0 1-4.784-4.786"
|
||||
/>
|
||||
<path
|
||||
fill="#FF7759"
|
||||
d="M4.118 15.23A4.117 4.117 0 0 0 0 19.348v.533a4.118 4.118 0 0 0 8.236 0v-.533a4.12 4.12 0 0 0-4.118-4.118z"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default Cohere;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Component = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.33}
|
||||
d="M5.5 8.5 9 12l-3.5 3.5L2 12zM12 2l3.5 3.5L12 9 8.5 5.5zM18.5 8.5 22 12l-3.5 3.5L15 12zM12 15l3.5 3.5L12 22l-3.5-3.5z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Component;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Condition = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m20.589 6.429-.001 10.285h2.555l-3.429 3.429-3.428-3.429h2.554V8.143H16.2a4.3 4.3 0 0 0 0-1.715zm-12.875.857q.001.441.086.857h-.943V8.14l-1.698.001v8.572h2.555l-3.428 3.429-3.429-3.429h2.554V6.43L7.8 6.428a4.4 4.4 0 0 0-.086.858M12 3.857a3.429 3.429 0 1 1 0 6.858 3.429 3.429 0 0 1 0-6.858m0 1.714A1.714 1.714 0 1 0 12 9a1.714 1.714 0 0 0 0-3.429"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Condition;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Copy = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M20 9h-9a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-9a2 2 0 0 0-2-2"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Copy;
|
|
@ -0,0 +1,26 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const CreateRecord = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g clipPath="url(#prefix__a)">
|
||||
<rect width={24} height={24} fill="#C4B5FD" rx={3} />
|
||||
<path
|
||||
fill="#A855F7"
|
||||
d="M17.01 11.01h-4.02V6.99a.99.99 0 1 0-1.98 0v4.02H6.99a.99.99 0 1 0 0 1.98h4.02v4.02a.99.99 0 1 0 1.98 0v-4.02h4.02a.99.99 0 1 0 0-1.98"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<rect width={24} height={24} fill="#fff" rx={3} />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default CreateRecord;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const CreditCard = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M20 5H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2M2 10h20"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default CreditCard;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Database = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 8c4.97 0 9-1.343 9-3s-4.03-3-9-3-9 1.343-9 3 4.03 3 9 3M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"
|
||||
/>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Database;
|
|
@ -0,0 +1,22 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const DeepThinking = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2.042 21.764c-1.35-1.349-1.527-3.655-.414-6.546.43-1.097.968-2.151 1.601-3.146L3.273 12l-.044-.072a18.6 18.6 0 0 1-1.604-3.142c-1.11-2.895-.933-5.201.417-6.552.744-.744 1.813-1.143 3.107-1.143 1.894 0 4.21.844 6.59 2.334l.071.044.07-.044c2.376-1.488 4.693-2.334 6.587-2.334 1.294 0 2.363.4 3.105 1.143 1.348 1.35 1.527 3.66.414 6.55a18.5 18.5 0 0 1-1.601 3.142l-.046.074.044.07c.665 1.062 1.21 2.123 1.603 3.144 1.113 2.89.936 5.2-.414 6.55-.742.744-1.811 1.143-3.103 1.143-1.896 0-4.21-.847-6.59-2.335l-.073-.043-.07.043c-2.378 1.49-4.695 2.337-6.59 2.337-1.293 0-2.362-.4-3.104-1.143zm18.122-5.848a15.5 15.5 0 0 0-.942-1.985l-.1-.175-.123.16a29.4 29.4 0 0 1-5.275 5.275l-.16.125.175.098c1.739.975 3.403 1.545 4.728 1.545.748 0 1.337-.184 1.724-.572.4-.4.582-1.03.571-1.79-.01-.763-.212-1.68-.598-2.683zM11.73 18.11l.077.057.078-.057a26.4 26.4 0 0 0 6.05-6.03l.057-.079-.056-.076a26.2 26.2 0 0 0-6.05-6.033l-.08-.055-.076.057a26.4 26.4 0 0 0-6.052 6.03L5.62 12l.057.079a26.3 26.3 0 0 0 6.052 6.032zm8.464-14.494c-.39-.388-.98-.571-1.726-.571-1.327 0-2.99.567-4.728 1.544l-.175.099.16.122a29.2 29.2 0 0 1 5.275 5.275l.122.16.099-.175c.375-.67.698-1.335.944-1.985.386-1 .59-1.916.598-2.68.011-.761-.17-1.39-.57-1.789M3.447 8.085q.404 1.027.945 1.986l.1.173.122-.16A29.2 29.2 0 0 1 9.888 4.81l.161-.122-.174-.099c-1.741-.977-3.404-1.544-4.73-1.544-.749 0-1.338.183-1.724.571-.4.4-.58 1.028-.57 1.79.01.763.212 1.68.596 2.68m0 7.831c-.386 1.002-.587 1.918-.595 2.682-.011.76.168 1.39.567 1.789.39.388.98.572 1.726.572 1.326 0 2.989-.568 4.728-1.545l.174-.098-.16-.125a29.2 29.2 0 0 1-5.273-5.275l-.124-.16-.098.175q-.542.961-.945 1.985"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.744 14.267a2.45 2.45 0 0 1-3.04-3.527 2.452 2.452 0 1 1 3.038 3.53z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default DeepThinking;
|
|
@ -0,0 +1,18 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Deepseek = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="#4D6BFE"
|
||||
d="M23.44 4.823c-.245-.123-.351.111-.495.23-.049.039-.09.089-.132.135-.36.392-.778.649-1.327.618-.802-.046-1.486.211-2.091.837-.129-.772-.556-1.232-1.206-1.528-.341-.154-.685-.307-.923-.641-.166-.238-.211-.503-.295-.765-.053-.157-.106-.318-.283-.345-.194-.03-.269.134-.345.272-.302.565-.42 1.187-.408 1.817.026 1.417.613 2.546 1.777 3.348.133.092.167.185.125.32-.08.275-.174.544-.257.82-.053.177-.132.216-.318.139a5.4 5.4 0 0 1-1.68-1.163c-.827-.818-1.576-1.72-2.51-2.427a11 11 0 0 0-.665-.465c-.953-.945.124-1.72.374-1.813.26-.096.09-.426-.753-.422s-1.614.292-2.597.676c-.144.058-.296.1-.45.134a9.1 9.1 0 0 0-2.788-.1c-1.822.208-3.278 1.087-4.348 2.589C.559 8.893.256 10.944.627 13.083c.39 2.254 1.517 4.12 3.249 5.58 1.796 1.512 3.864 2.253 6.224 2.111 1.433-.084 3.029-.28 4.829-1.835.454.23.93.323 1.72.392.61.057 1.195-.031 1.65-.127.71-.154.66-.826.404-.949-2.084-.99-1.626-.587-2.042-.913 1.059-1.28 2.654-2.608 3.278-6.912.05-.342.008-.557 0-.834-.004-.169.034-.234.224-.253a4 4 0 0 0 1.493-.469c1.35-.752 1.895-1.989 2.023-3.471.02-.227-.003-.461-.238-.58m-11.763 13.34c-2.02-1.62-3-2.154-3.404-2.131-.378.023-.31.465-.227.753.087.284.201.48.36.73.11.164.185.41-.11.594-.65.411-1.78-.138-1.834-.165-1.316-.79-2.417-1.835-3.192-3.264a10.1 10.1 0 0 1-1.255-4.423c-.02-.38.09-.515.46-.584a4.4 4.4 0 0 1 1.48-.039c2.06.308 3.816 1.249 5.286 2.738.84.849 1.475 1.863 2.13 2.854.695 1.052 1.444 2.054 2.397 2.876.336.288.605.506.862.668-.775.088-2.069.107-2.953-.607m.968-6.355a.3.3 0 0 1 .4-.284.3.3 0 0 1 .194.284.3.3 0 0 1-.184.28.3.3 0 0 1-.23 0 .3.3 0 0 1-.18-.28m3.006 1.574c-.192.081-.386.15-.571.158-.287.015-.601-.104-.771-.25-.265-.226-.454-.353-.533-.749a1.7 1.7 0 0 1 .014-.58c.069-.322-.007-.53-.23-.718-.181-.153-.412-.195-.666-.195a.53.53 0 0 1-.327-.14.25.25 0 0 1-.06-.193.3.3 0 0 1 .032-.097c.027-.054.155-.185.185-.208.345-.2.742-.134 1.108.016.34.142.597.403.968.771.379.446.447.569.662.903.17.26.325.53.43.837.066.192-.018.35-.241.445"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Deepseek;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const DivideCircle = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
clipPath="url(#prefix__a)"
|
||||
>
|
||||
<path d="M8 12h8M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default DivideCircle;
|
|
@ -0,0 +1,28 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const DivideSquare = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
clipPath="url(#prefix__a)"
|
||||
>
|
||||
<path d="M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2M8 12h8" />
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="prefix__a">
|
||||
<path fill="#fff" d="M0 0h24v24H0z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
export default DivideSquare;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const DollarSign = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M12 2v20M17 5H9.5a3.5 3.5 0 1 0 0 7h5a3.5 3.5 0 1 1 0 7H6"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default DollarSign;
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import type { SVGProps } from 'react';
|
||||
const Download = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default Download;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue