├── .env.example ├── .eslintrc.json ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── .vscode └── settings.json ├── Dockerfile ├── README.md ├── README_ja.md ├── README_zh.md ├── components.json ├── next.config.mjs ├── package-lock.json ├── package.json ├── pm2-deploy.cjs ├── postcss.config.cjs ├── prettier.config.js ├── public ├── favicon.ico └── images │ └── global │ ├── DEV-KIT.png │ ├── logo-dark.png │ ├── logo-light.png │ └── logo-mini.png ├── src ├── app │ └── [locale] │ │ ├── (land) │ │ ├── _components │ │ │ ├── header │ │ │ │ └── index.tsx │ │ │ └── test │ │ │ │ └── index.tsx │ │ └── page.tsx │ │ ├── auth │ │ └── page.tsx │ │ ├── layout.tsx │ │ └── loading.tsx ├── components │ ├── common │ │ ├── form-generator │ │ │ └── index.tsx │ │ ├── loader-renderer │ │ │ └── index.tsx │ │ ├── skeleton-renderer │ │ │ └── index.tsx │ │ └── trans-renderer │ │ │ └── index.tsx │ ├── forms │ │ └── auth │ │ │ ├── index.tsx │ │ │ └── schema.ts │ ├── global │ │ ├── app-auth │ │ │ └── index.tsx │ │ ├── app-chat │ │ │ └── index.tsx │ │ ├── app-client │ │ │ └── index.tsx │ │ ├── app-footer │ │ │ └── index.tsx │ │ ├── app-logo │ │ │ └── index.tsx │ │ ├── app-message │ │ │ └── index.tsx │ │ ├── app-navbar │ │ │ ├── index.tsx │ │ │ ├── info-modal.tsx │ │ │ ├── lang-switcher.tsx │ │ │ └── theme-switcher.tsx │ │ ├── app-query │ │ │ └── index.tsx │ │ └── app-theme │ │ │ └── index.tsx │ └── ui │ │ ├── alert-dialog.tsx │ │ ├── button.tsx │ │ ├── checkbox.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── skeleton.tsx │ │ ├── textarea.tsx │ │ ├── toast.tsx │ │ └── toaster.tsx ├── constants │ ├── forms.ts │ ├── index.ts │ ├── menus.tsx │ └── options.ts ├── env.ts ├── hooks │ ├── auth │ │ └── index.ts │ └── global │ │ ├── index.ts │ │ ├── use-client-translation.ts │ │ ├── use-domain.ts │ │ ├── use-info.ts │ │ ├── use-is-authed.ts │ │ ├── use-is-mobile.ts │ │ ├── use-locale-router.ts │ │ ├── use-theme.ts │ │ └── use-toast.ts ├── i18n │ ├── client.ts │ ├── config.ts │ ├── index.ts │ └── locales │ │ ├── en │ │ ├── auth.json │ │ ├── global.json │ │ └── land.json │ │ ├── ja │ │ ├── auth.json │ │ ├── global.json │ │ └── land.json │ │ └── zh │ │ ├── auth.json │ │ ├── global.json │ │ └── land.json ├── icons │ ├── auth.tsx │ ├── global.tsx │ └── index.tsx ├── lib │ ├── api.ts │ ├── mitt.ts │ └── utils.ts ├── middleware.ts ├── services │ └── auth.ts ├── stores │ ├── index.ts │ └── slices │ │ └── config-slice.ts ├── styles │ ├── globals.css │ └── info.css └── types │ └── index.ts ├── tailwind.config.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | # Env Example 2 | 3 | # [Auth Way: 1 OR 2] 4 | # 1.Use API-Key: Please view visit 302.ai 5 | NEXT_PUBLIC_302_API_KEY="sk-XXX" 6 | 7 | # 2.Use Auth API 8 | # NEXT_PUBLIC_DEV_HOST_NAME=YOUR_DEV_HOST # Remind only use it bor dev 9 | NEXT_PUBLIC_AUTH_PATH=/auth 10 | NEXT_PUBLIC_AUTH_API_URL=https://test-api2.gpt302.com 11 | 12 | 13 | # [API and Model] 14 | # 302.AI Base API URL 15 | NEXT_PUBLIC_API_URL=https://test-api.gpt302.com 16 | # Base AI model 17 | NEXT_PUBLIC_DEFAULT_MODEL_NAME=gpt-4o-mini 18 | 19 | 20 | # [Locale Settings] 21 | # Default region 22 | NEXT_PUBLIC_DEFAULT_REGION=0 23 | # Default language for locale 24 | NEXT_PUBLIC_DEFAULT_LOCALE=en 25 | # 302AI website URL 26 | NEXT_PUBLIC_OFFICIAL_WEBSITE_URL_GLOBAL=https://302.ai/ 27 | NEXT_PUBLIC_OFFICIAL_WEBSITE_URL_CHINA=https://302ai.cn/ 28 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "next/core-web-vitals", 4 | "next/typescript", 5 | "prettier", 6 | "plugin:tailwindcss/recommended" 7 | ], 8 | "plugins": ["tailwindcss", "check-file", "n"], 9 | "rules": { 10 | "prefer-arrow-callback": ["error"], 11 | "prefer-template": ["error"], 12 | // "semi": [ 13 | // "error" 14 | // ], 15 | "quotes": ["error", "double"], 16 | // "n/no-process-env": ["error"], 17 | "tailwindcss/enforces-shorthand": "off", 18 | "@typescript-eslint/no-empty-object-type": "off", 19 | "tailwindcss/no-custom-classname": "off", 20 | "n/no-process-env": "off", 21 | "check-file/filename-naming-convention": [ 22 | "error", 23 | { 24 | "**/*.{ts,tsx}": "KEBAB_CASE" 25 | }, 26 | { 27 | "ignoreMiddleExtensions": true 28 | } 29 | ], 30 | "check-file/folder-naming-convention": [ 31 | "error", 32 | { 33 | "src/**/!^[.*": "KEBAB_CASE" 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # database 12 | /prisma/db.sqlite 13 | /prisma/db.sqlite-journal 14 | db.sqlite 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | next-env.d.ts 20 | 21 | # production 22 | /build 23 | 24 | # misc 25 | .DS_Store 26 | *.pem 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | .pnpm-debug.log* 33 | 34 | # local env files 35 | # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables 36 | .env 37 | .env*.local 38 | 39 | # vercel 40 | .vercel 41 | 42 | # typescript 43 | *.tsbuildinfo 44 | 45 | # idea files 46 | .idea -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | src/components/ui -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": false, 4 | "tabWidth": 2, 5 | "trailingComma": "es5", 6 | "importOrder": [ 7 | "^(react|next?/?([a-zA-Z/]*))$", 8 | "", 9 | "^@/(.*)$", 10 | "^[./]" 11 | ], 12 | "importOrderSeparation": true, 13 | "importOrderSortSpecifiers": true, 14 | "plugins": [ 15 | "@trivago/prettier-plugin-sort-imports", 16 | "prettier-plugin-tailwindcss" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll": "always", 5 | "source.organizeImports": "always" 6 | }, 7 | "files.associations": { 8 | "*.css": "tailwindcss" 9 | }, 10 | "typescript.tsdk": "node_modules/typescript/lib", 11 | "compile-hero.disable-compile-files-on-did-save-code": true, 12 | "i18n-ally.localesPaths": ["src/i18n/locales"], 13 | "i18n-ally.sourceLanguage": "zh", // 根据此语言文件翻译 14 | "i18n-ally.displayLanguage": "zh", // 编辑器默认显示语言 15 | "i18n-ally.keystyle": "nested", // 翻译后变量格式 16 | "i18n-ally.preferredDelimiter": "_", // 翻译后变量分隔符 17 | "i18n-ally.sortKeys": true, // 翻译后变量排序 18 | "i18n-ally.namespace": true, // 翻译后命名空间 19 | "i18n-ally.enabledParsers": ["json"], // 支持的翻译文件类型(json文件支持写入,js文件只有读取的权限) 20 | "i18n-ally.extract.autoDetect": false // 自动检测翻译文件 21 | } 22 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Base image 2 | FROM node:20.14-alpine AS base 3 | 4 | # Install dependencies only when needed 5 | FROM base AS deps 6 | # Set mirror source to USTC mirror 7 | RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories 8 | RUN apk update 9 | # Install compatibility libraries 10 | RUN apk add --no-cache libc6-compat 11 | WORKDIR /app 12 | 13 | # Copy dependency files 14 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ 15 | 16 | # Install dependencies according to package manager 17 | RUN \ 18 | if [ -f yarn.lock ]; then \ 19 | corepack enable && \ 20 | yarn --frozen-lockfile; \ 21 | elif [ -f package-lock.json ]; then \ 22 | npm config set registry https://registry.npmmirror.com && \ 23 | npm ci; \ 24 | elif [ -f pnpm-lock.yaml ]; then \ 25 | corepack enable pnpm && \ 26 | pnpm config set registry https://registry.npmmirror.com && \ 27 | pnpm i --frozen-lockfile; \ 28 | else \ 29 | echo "Lock file not found." && exit 1; \ 30 | fi 31 | 32 | # Rebuild source code only when needed 33 | FROM base AS builder 34 | WORKDIR /app 35 | 36 | # Copy dependencies and source code 37 | COPY --from=deps /app/node_modules ./node_modules 38 | COPY . . 39 | 40 | # Execute build according to build mode 41 | RUN corepack enable pnpm && pnpm run build; 42 | 43 | 44 | # Production image, copy all files and run Next.js 45 | FROM base AS runner 46 | WORKDIR /app 47 | 48 | # Create a non-root user 49 | RUN addgroup --system --gid 1001 nodejs 50 | RUN adduser --system --uid 1001 nextjs 51 | 52 | # Copy static files 53 | COPY --from=builder /app/public ./public 54 | 55 | # Set permissions for pre-rendered cache 56 | RUN mkdir .next 57 | RUN chown nextjs:nodejs .next 58 | 59 | # Copy build artifacts 60 | COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ 61 | COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static 62 | 63 | # Copy .env file 64 | COPY --chown=nextjs:nodejs .env .env 65 | 66 | # Switch to non-root user 67 | USER nextjs 68 | 69 | # Expose port 70 | EXPOSE 3000 71 | 72 | # Set environment variables 73 | ENV PORT=3000 74 | 75 | # Start command 76 | CMD HOSTNAME="0.0.0.0" node server.js 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #

🤖 302-Dev-Kit🚀✨

2 | 3 |

302-Dev-Kit is a Next.js-based Web project aimed at providing a fast and efficient development experience based on the 302.AI API. This project includes basic components, hooks, and utility functions to help developers quickly build production-grade AI tool applications.

4 | 5 |

6 | 7 |

中文 | English | 日本語

8 | 9 | ![](public//images/global//DEV-KIT.png) 10 | 11 | ## Features 12 | 13 | - **Component-based Development**: Clear project structure with well-defined components, including public components, form components, global components, and basic components. 14 | - **State Management**: Uses Zustand for state management. 15 | - **Internationalization Support**: Built-in multi-language support (Chinese, English, Japanese). 16 | - **Rich Utility Functions**: Includes API requests, authentication, event dispatching, and other utility functions. 17 | - **Code Standards**: Uses ESLint and Prettier for code checking and formatting. 18 | 19 | ## Directory Structure 20 | 21 | ```plaintext 22 | root 23 | ├── src 24 | │ ├── app 25 | │ ├── layout // Root layout 26 | │ │── auth // Authentication page 27 | │ │ ├── index // Export module 28 | │ │ ├── _components // Private components 29 | │ ├── (land) // Landing page group 30 | │ │ │── page // Main landing page 31 | │ │ │── _components // Private components 32 | │ ├── components // Public components 33 | │ │ ├── common // Common components 34 | │ │ ├── forms // Form components 35 | │ │ ├── global // Global components 36 | │ │ ├── ui // Basic components 37 | │ ├── constants // Constants 38 | │ │ ├── forms // Form-related constants 39 | │ │ ├── menus // Menu options 40 | │ ├── hooks // Hooks 41 | │ │ ├── auth // Authentication module hooks 42 | │ │ ├── global // Global hooks 43 | │ ├── icons // Icons 44 | │ │ ├── auth // Authentication module icons 45 | │ │ ├── global // Global module icons 46 | │ ├── lib // Utility functions 47 | │ │ ├── api // Request-related utility functions 48 | │ │ ├── mitt // Event dispatching tool 49 | │ │ ├── utils // Other utility sets 50 | │ ├── services // Request functions 51 | │ │ ├── auth // Authentication requests 52 | │ ├── locales // Internationalization 53 | │ │ ├── zh // Chinese 54 | │ │ ├── en // English 55 | │ │ ├── ja // Japanese 56 | │ ├── stores // State management 57 | │ │ ├── slices // Divided module states 58 | │ │ ├── index // Export module 59 | │ ├── styles // Styles 60 | │ │ ├── global // Global styles 61 | │ │ ├── info // Information styles 62 | │ ├── env.ts // Environment variable control 63 | └── package.json 64 | ``` 65 | 66 | ## Installation 67 | 68 | 1. Clone the repository: 69 | 70 | ```bash 71 | git clone https://github.com/302ai/302-Dev-Kit 72 | ``` 73 | 74 | 2. Install dependencies: 75 | 76 | ```bash 77 | cd 302-Dev-Kit 78 | npm install 79 | ``` 80 | 81 | ## Script Commands 82 | 83 | - `npm run build`: Build for production environment. 84 | - `npm run dev`: Start development environment. 85 | - `npm run lint`: Run ESLint for code checking. 86 | - `npm run start`: Start production environment. 87 | - `npm run clean`: Clean generated build files. 88 | - `npm run check`: Check code format. 89 | - `npm run format`: Format code. 90 | 91 | ## Dependencies 92 | 93 | ### Production Dependencies 94 | 95 | - `@hookform/error-message` 96 | - `@hookform/resolvers` 97 | - `@radix-ui/react-alert-dialog` 98 | - `@radix-ui/react-checkbox` 99 | - `@radix-ui/react-dialog` 100 | - `@radix-ui/react-dropdown-menu` 101 | - `@radix-ui/react-icons` 102 | - `@radix-ui/react-label` 103 | - `@radix-ui/react-slot` 104 | - `@radix-ui/react-toast` 105 | - `@t3-oss/env-nextjs` 106 | - `@tanstack/react-query` 107 | - `ahooks` 108 | - `class-variance-authority` 109 | - `clsx` 110 | - `geist` 111 | - `jiti` 112 | - `ky` 113 | - `ll` 114 | - `lucide-react` 115 | - `mitt` 116 | - `next` 117 | - `next-themes` 118 | - `react` 119 | - `react-dom` 120 | - `react-hook-form` 121 | - `tailwind-merge` 122 | - `tailwindcss-animate` 123 | - `zod` 124 | - `zustand` 125 | 126 | ### Development Dependencies 127 | 128 | - `@trivago/prettier-plugin-sort-imports` 129 | - `@types/eslint` 130 | - `@types/node` 131 | - `@types/react` 132 | - `@types/react-dom` 133 | - `@typescript-eslint/eslint-plugin` 134 | - `@typescript-eslint/parser` 135 | - `eslint` 136 | - `eslint-config-next` 137 | - `eslint-config-prettier` 138 | - `eslint-plugin-check-file` 139 | - `eslint-plugin-n` 140 | - `eslint-plugin-tailwindcss` 141 | - `postcss` 142 | - `prettier` 143 | - `prettier-plugin-tailwindcss` 144 | - `tailwindcss` 145 | - `typescript` 146 | 147 | ## Development Guide 148 | 149 | ### Start Development Environment 150 | 151 | ```bash 152 | npm run dev 153 | ``` 154 | 155 | ### Build Production Environment 156 | 157 | ```bash 158 | npm run build 159 | ``` 160 | 161 | ## Code Style and Standards 162 | 163 | Use ESLint for code checking and Prettier for code formatting. Please ensure your code passes checks and formatting before submitting. 164 | 165 | ```bash 166 | npm run lint 167 | npm run format 168 | ``` 169 | 170 | ## Internationalization 171 | 172 | The project supports multiple languages, currently including Chinese, English, and Japanese. Language files are stored in the `src/locales` directory. 173 | 174 | ## License 175 | 176 | This project is licensed under the MIT License. 177 | -------------------------------------------------------------------------------- /README_ja.md: -------------------------------------------------------------------------------- 1 | #

🤖 302-Dev-Kit🚀✨

2 | 3 |

302-Dev-Kitは、302.AIのAPIをベースにした、高速で効率的な開発体験を提供することを目的としたNext.jsベースのWebプロジェクトです。このプロジェクトには、基本的なコンポーネント、フック、ユーティリティ関数が含まれており、開発者が本番環境レベルのAIツールアプリケーションを迅速に構築するのに役立ちます。

4 | 5 |

6 | 7 |

中文 | English | 日本語

8 | 9 | ![](public//images/global//DEV-KIT.png) 10 | 11 | ## 機能特性 12 | 13 | - **コンポーネントベースの開発**: プロジェクト構造が明確で、コンポーネントの区分が明確です。公共コンポーネント、フォームコンポーネント、グローバルコンポーネント、基本コンポーネントが含まれています。 14 | - **状態管理**: Zustandを使用して状態管理を行います。 15 | - **国際化サポート**: 多言語サポート(中国語、英語、日本語)が組み込まれています。 16 | - **豊富なユーティリティ関数**: APIリクエスト、認証、イベントディスパッチなどのユーティリティ関数が含まれています。 17 | - **コード規約**: ESLintとPrettierを使用してコードチェックとフォーマットを行います。 18 | 19 | ## ディレクトリ構造 20 | 21 | ```plaintext 22 | root 23 | ├── src 24 | │ ├── app 25 | │ ├── layout // ルートレイアウト 26 | │ │── auth // 認証ページ 27 | │ │ ├── index // エクスポートモジュール 28 | │ │ ├── _components // プライベートコンポーネント 29 | │ ├── (land) // ランディングページグループ 30 | │ │ │── page // メインランディングページ 31 | │ │ │── _components // プライベートコンポーネント 32 | │ ├── components // 公共コンポーネント 33 | │ │ ├── common // 共通コンポーネント 34 | │ │ ├── forms // フォームコンポーネント 35 | │ │ ├── global // グローバルコンポーネント 36 | │ │ ├── ui // 基本コンポーネント 37 | │ ├── constants // 定数 38 | │ │ ├── forms // フォーム関連の定数 39 | │ │ ├── menus // メニューオプション 40 | │ ├── hooks // フック 41 | │ │ ├── auth // 認証モジュールのフック 42 | │ │ ├── global // グローバルフック 43 | │ ├── icons // アイコン 44 | │ │ ├── auth // 認証モジュールのアイコン 45 | │ │ ├── global // グローバルモジュールのアイコン 46 | │ ├── lib // ユーティリティ関数 47 | │ │ ├── api // リクエスト関連のユーティリティ関数 48 | │ │ ├── mitt // イベントディスパッチツール 49 | │ │ ├── utils // その他のユーティリティセット 50 | │ ├── services // リクエスト関数 51 | │ │ ├── auth // 認証リクエスト 52 | │ ├── locales // 国際化 53 | │ │ ├── zh // 中国語 54 | │ │ ├── en // 英語 55 | │ │ ├── ja // 日本語 56 | │ ├── stores // 状態管理 57 | │ │ ├── slices // モジュール状態の分割 58 | │ │ ├── index // エクスポートモジュール 59 | │ ├── styles // スタイル 60 | │ │ ├── global // グローバルスタイル 61 | │ │ ├── info // 情報スタイル 62 | │ ├── env.ts // 環境変数制御 63 | └── package.json 64 | ``` 65 | 66 | ## インストール 67 | 68 | 1. リポジトリをクローンします: 69 | 70 | ```bash 71 | git clone https://github.com/302ai/302-Dev-Kit 72 | ``` 73 | 74 | 2. 依存関係をインストールします: 75 | 76 | ```bash 77 | cd 302-Dev-Kit 78 | npm install 79 | ``` 80 | 81 | ## スクリプトコマンド 82 | 83 | - `npm run build`: 本番環境用にビルドします。 84 | - `npm run dev`: 開発環境を起動します。 85 | - `npm run lint`: ESLintを実行してコードチェックを行います。 86 | - `npm run start`: 本番環境を起動します。 87 | - `npm run clean`: 生成されたビルドファイルをクリーンアップします。 88 | - `npm run check`: コードフォーマットをチェックします。 89 | - `npm run format`: コードをフォーマットします。 90 | 91 | ## 依存関係 92 | 93 | ### 本番依存関係 94 | 95 | - `@hookform/error-message` 96 | - `@hookform/resolvers` 97 | - `@radix-ui/react-alert-dialog` 98 | - `@radix-ui/react-checkbox` 99 | - `@radix-ui/react-dialog` 100 | - `@radix-ui/react-dropdown-menu` 101 | - `@radix-ui/react-icons` 102 | - `@radix-ui/react-label` 103 | - `@radix-ui/react-slot` 104 | - `@radix-ui/react-toast` 105 | - `@t3-oss/env-nextjs` 106 | - `@tanstack/react-query` 107 | - `ahooks` 108 | - `class-variance-authority` 109 | - `clsx` 110 | - `geist` 111 | - `jiti` 112 | - `ky` 113 | - `ll` 114 | - `lucide-react` 115 | - `mitt` 116 | - `next` 117 | - `next-themes` 118 | - `react` 119 | - `react-dom` 120 | - `react-hook-form` 121 | - `tailwind-merge` 122 | - `tailwindcss-animate` 123 | - `zod` 124 | - `zustand` 125 | 126 | ### 開発依存関係 127 | 128 | - `@trivago/prettier-plugin-sort-imports` 129 | - `@types/eslint` 130 | - `@types/node` 131 | - `@types/react` 132 | - `@types/react-dom` 133 | - `@typescript-eslint/eslint-plugin` 134 | - `@typescript-eslint/parser` 135 | - `eslint` 136 | - `eslint-config-next` 137 | - `eslint-config-prettier` 138 | - `eslint-plugin-check-file` 139 | - `eslint-plugin-n` 140 | - `eslint-plugin-tailwindcss` 141 | - `postcss` 142 | - `prettier` 143 | - `prettier-plugin-tailwindcss` 144 | - `tailwindcss` 145 | - `typescript` 146 | 147 | ## 開発ガイド 148 | 149 | ### 開発環境の起動 150 | 151 | ```bash 152 | npm run dev 153 | ``` 154 | 155 | ### 本番環境のビルド 156 | 157 | ```bash 158 | npm run build 159 | ``` 160 | 161 | ## コードスタイルと規約 162 | 163 | ESLintを使用してコードチェックを行い、Prettierを使用してコードフォーマットを行います。コードを提出する前に、チェックとフォーマットを通過していることを確認してください。 164 | 165 | ```bash 166 | npm run lint 167 | npm run format 168 | ``` 169 | 170 | ## 国際化 171 | 172 | このプロジェクトは複数の言語をサポートしており、現在中国語、英語、日本語をサポートしています。言語ファイルは `src/locales` ディレクトリに保存されています。 173 | 174 | ## ライセンス 175 | 176 | このプロジェクトはMITライセンスの下で提供されています。 177 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | #

🤖 302-Dev-Kit🚀✨

2 | 3 |

302-Dev-Kit是一个基于 Next.js 的 Web 项目,旨在基于302.AI的API基础上,提供快速、高效的开发体验。本项目包含基础的组件、钩子以及工具函数,助力开发者快速搭建生产级AI工具应用。

4 | 5 |

6 | 7 |

中文 | English | 日本語

8 | 9 | ![](public//images/global//DEV-KIT.png) 10 | ## 功能特性 11 | 12 | - **组件化开发**: 项目结构清晰,组件划分明确,包括公共组件、表单组件、全局组件和基础组件。 13 | - **状态管理**: 使用 Zustand 进行状态管理。 14 | - **国际化支持**: 内置多语言支持(中文、英文、日文)。 15 | - **丰富的工具函数**: 包含 API 请求、鉴权、事件派发等工具函数。 16 | - **代码规范**: 使用 ESLint 和 Prettier 进行代码检查和格式化。 17 | 18 | ## 目录结构 19 | 20 | ```plaintext 21 | root 22 | ├── src 23 | │ ├── app 24 | │ ├── layout // 根部布局 25 | │ │── auth // 鉴权页 26 | │ │ ├── index // 导出模块 27 | │ │ ├── _components // 私有组件 28 | │ ├── (land) // 落地页组 29 | │ │ │── page // 落地主页 30 | │ │ │── _components // 私有组件 31 | │ ├── components // 公共组件 32 | │ │ ├── common // 通用组件 33 | │ │ ├── forms // 表单组件 34 | │ │ ├── global // 全局组件 35 | │ │ ├── ui // 基础组件 36 | │ ├── constants // 常量 37 | │ │ ├── forms // 表单相关常量 38 | │ │ ├── menus // 菜单选项 39 | │ ├── hooks // 钩子 40 | │ │ ├── auth // 认证模块钩子 41 | │ │ ├── global // 全局钩子 42 | │ ├── icons // 图标 43 | │ │ ├── auth // 认证模块的图标 44 | │ │ ├── global // 全局模块图标 45 | │ ├── lib // 工具函数 46 | │ │ ├── api // 请求相关工具函数 47 | │ │ ├── mitt // 事件派发工具 48 | │ │ ├── utils // 其他工具集 49 | │ ├── services // 请求函数 50 | │ │ ├── auth // 鉴权请求 51 | │ ├── locales // 国际化 52 | │ │ ├── zh // 中文 53 | │ │ ├── en // 英文 54 | │ │ ├── ja // 日文 55 | │ ├── stores // 状态管理 56 | │ │ ├── slices // 划分模块状态 57 | │ │ ├── index // 导出模块 58 | │ ├── styles // 样式 59 | │ │ ├── global // 全局样式 60 | │ │ ├── info // 信息样式 61 | │ ├── env.ts // 环境变量控制 62 | └── package.json 63 | ``` 64 | 65 | ## 安装 66 | 67 | 1. 克隆仓库: 68 | 69 | ```bash 70 | git clone https://github.com/302ai/302-Dev-Kit 71 | ``` 72 | 73 | 2. 安装依赖: 74 | 75 | ```bash 76 | cd 302-Dev-Kit 77 | npm install 78 | ``` 79 | 80 | ## 脚本命令 81 | 82 | - `npm run build`:构建生产环境。 83 | - `npm run dev`:启动开发环境。 84 | - `npm run lint`:运行 ESLint 进行代码检查。 85 | - `npm run start`:启动生产环境。 86 | - `npm run clean`:清理生成的构建文件。 87 | - `npm run check`:检查代码格式。 88 | - `npm run format`:格式化代码。 89 | 90 | ## 依赖 91 | 92 | ### 生产依赖 93 | 94 | - `@hookform/error-message` 95 | - `@hookform/resolvers` 96 | - `@radix-ui/react-alert-dialog` 97 | - `@radix-ui/react-checkbox` 98 | - `@radix-ui/react-dialog` 99 | - `@radix-ui/react-dropdown-menu` 100 | - `@radix-ui/react-icons` 101 | - `@radix-ui/react-label` 102 | - `@radix-ui/react-slot` 103 | - `@radix-ui/react-toast` 104 | - `@t3-oss/env-nextjs` 105 | - `@tanstack/react-query` 106 | - `ahooks` 107 | - `class-variance-authority` 108 | - `clsx` 109 | - `geist` 110 | - `jiti` 111 | - `ky` 112 | - `ll` 113 | - `lucide-react` 114 | - `mitt` 115 | - `next` 116 | - `next-themes` 117 | - `react` 118 | - `react-dom` 119 | - `react-hook-form` 120 | - `tailwind-merge` 121 | - `tailwindcss-animate` 122 | - `zod` 123 | - `zustand` 124 | 125 | ### 开发依赖 126 | 127 | - `@trivago/prettier-plugin-sort-imports` 128 | - `@types/eslint` 129 | - `@types/node` 130 | - `@types/react` 131 | - `@types/react-dom` 132 | - `@typescript-eslint/eslint-plugin` 133 | - `@typescript-eslint/parser` 134 | - `eslint` 135 | - `eslint-config-next` 136 | - `eslint-config-prettier` 137 | - `eslint-plugin-check-file` 138 | - `eslint-plugin-n` 139 | - `eslint-plugin-tailwindcss` 140 | - `postcss` 141 | - `prettier` 142 | - `prettier-plugin-tailwindcss` 143 | - `tailwindcss` 144 | - `typescript` 145 | 146 | ## 开发指南 147 | 148 | ### 启动开发环境 149 | 150 | ```bash 151 | npm run dev 152 | ``` 153 | 154 | ### 构建生产环境 155 | 156 | ```bash 157 | npm run build 158 | ``` 159 | 160 | ## 代码风格和规范 161 | 162 | 使用 ESLint 进行代码检查,Prettier 进行代码格式化。请在提交代码前确保代码通过检查和格式化。 163 | 164 | ```bash 165 | npm run lint 166 | npm run format 167 | ``` 168 | 169 | ## 国际化 170 | 171 | 项目支持多种语言,当前支持中文、英文和日文。语言文件存储在 `src/locales` 目录下。 172 | 173 | ## License 174 | 175 | 此项目使用 MIT 许可证。 176 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "stone", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | import createJiti from "jiti"; 2 | import { fileURLToPath } from "node:url"; 3 | 4 | const jiti = createJiti(fileURLToPath(import.meta.url)); 5 | 6 | jiti("./src/env"); 7 | 8 | /** @type {import('next').NextConfig} */ 9 | const nextConfig = { 10 | reactStrictMode: false, 11 | // output: "standalone", 12 | experimental: { 13 | typedRoutes: true, 14 | }, 15 | images: { 16 | remotePatterns: [ 17 | { 18 | protocol: "https", 19 | hostname: "file.302.ai", 20 | }, 21 | ], 22 | }, 23 | }; 24 | 25 | export default nextConfig; 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tool-start", 3 | "version": "0.1.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "next build", 8 | "dev": "next dev", 9 | "lint": "next lint", 10 | "start": "next start", 11 | "clean": "rm -rf src/**/dist", 12 | "check": "prettier --check .", 13 | "format": "prettier --write .", 14 | "prepare": "husky" 15 | }, 16 | "dependencies": { 17 | "@formatjs/intl-localematcher": "^0.5.5", 18 | "@hookform/error-message": "^2.0.1", 19 | "@hookform/resolvers": "^3.9.0", 20 | "@radix-ui/react-alert-dialog": "^1.1.1", 21 | "@radix-ui/react-checkbox": "^1.1.1", 22 | "@radix-ui/react-dialog": "^1.1.1", 23 | "@radix-ui/react-dropdown-menu": "^2.1.1", 24 | "@radix-ui/react-icons": "^1.3.0", 25 | "@radix-ui/react-label": "^2.1.0", 26 | "@radix-ui/react-slot": "^1.1.0", 27 | "@radix-ui/react-toast": "^1.2.1", 28 | "@t3-oss/env-nextjs": "^0.10.1", 29 | "@tanstack/react-query": "^5.56.2", 30 | "ahooks": "^3.8.1", 31 | "class-variance-authority": "^0.7.0", 32 | "clsx": "^2.1.1", 33 | "geist": "^1.3.0", 34 | "i18next": "^23.16.2", 35 | "i18next-browser-languagedetector": "^8.0.0", 36 | "i18next-resources-to-backend": "^1.2.1", 37 | "immer": "^10.1.1", 38 | "jiti": "^1.21.6", 39 | "ky": "^1.7.2", 40 | "ll": "^1.2.0", 41 | "lucide-react": "^0.445.0", 42 | "mitt": "^3.0.1", 43 | "negotiator": "^1.0.0", 44 | "next": "^14.2.4", 45 | "next-themes": "^0.3.0", 46 | "react": "^18.3.1", 47 | "react-cookie": "^7.2.1", 48 | "react-dom": "^18.3.1", 49 | "react-hook-form": "^7.53.0", 50 | "react-i18next": "^15.0.3", 51 | "tailwind-merge": "^2.5.2", 52 | "tailwindcss-animate": "^1.0.7", 53 | "zod": "^3.23.8", 54 | "zustand": "^5.0.0-rc.2" 55 | }, 56 | "devDependencies": { 57 | "@trivago/prettier-plugin-sort-imports": "^4.3.0", 58 | "@types/eslint": "^8.56.10", 59 | "@types/negotiator": "^0.6.3", 60 | "@types/node": "^20.14.10", 61 | "@types/react": "^18.3.3", 62 | "@types/react-dom": "^18.3.0", 63 | "@typescript-eslint/eslint-plugin": "^8.1.0", 64 | "@typescript-eslint/parser": "^8.1.0", 65 | "eslint": "^8.57.0", 66 | "eslint-config-next": "^14.2.13", 67 | "eslint-config-prettier": "^9.1.0", 68 | "eslint-plugin-check-file": "^2.8.0", 69 | "eslint-plugin-n": "^17.10.3", 70 | "eslint-plugin-tailwindcss": "^3.17.4", 71 | "husky": "^9.1.6", 72 | "lint-staged": "^15.2.10", 73 | "postcss": "^8.4.39", 74 | "prettier": "^3.3.3", 75 | "prettier-plugin-tailwindcss": "^0.6.5", 76 | "tailwindcss": "^3.4.3", 77 | "typescript": "^5.5.3" 78 | }, 79 | "ct3aMetadata": { 80 | "initVersion": "7.37.0" 81 | }, 82 | "packageManager": "npm@10.1.0", 83 | "lint-staged": { 84 | "*.{js,jsx,ts,tsx,css,md}": [ 85 | "prettier --write" 86 | ] 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /pm2-deploy.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: "302AI-Dev-Kit", 5 | script: "./node_modules/next/dist/bin/next", 6 | args: "start -p 3000", 7 | env: { 8 | NODE_ENV: "production", 9 | }, 10 | }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: { 3 | tailwindcss: {}, 4 | }, 5 | }; 6 | 7 | module.exports = config; 8 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */ 2 | const config = { 3 | plugins: ["prettier-plugin-tailwindcss"], 4 | }; 5 | 6 | export default config; 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/302ai/302-Dev-Kit/8a85229059ad59f11725048744b9694f92106a29/public/favicon.ico -------------------------------------------------------------------------------- /public/images/global/DEV-KIT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/302ai/302-Dev-Kit/8a85229059ad59f11725048744b9694f92106a29/public/images/global/DEV-KIT.png -------------------------------------------------------------------------------- /public/images/global/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/302ai/302-Dev-Kit/8a85229059ad59f11725048744b9694f92106a29/public/images/global/logo-dark.png -------------------------------------------------------------------------------- /public/images/global/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/302ai/302-Dev-Kit/8a85229059ad59f11725048744b9694f92106a29/public/images/global/logo-light.png -------------------------------------------------------------------------------- /public/images/global/logo-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/302ai/302-Dev-Kit/8a85229059ad59f11725048744b9694f92106a29/public/images/global/logo-mini.png -------------------------------------------------------------------------------- /src/app/[locale]/(land)/_components/header/index.tsx: -------------------------------------------------------------------------------- 1 | import AppLogo from "@/components/global/app-logo"; 2 | 3 | type Props = { 4 | title: string; 5 | }; 6 | 7 | const LandHeader = (props: Props) => { 8 | return ( 9 |
10 |
11 | 17 |

{props.title}

18 |
19 |
20 | ); 21 | }; 22 | 23 | export default LandHeader; 24 | -------------------------------------------------------------------------------- /src/app/[locale]/(land)/_components/test/index.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useEffect } from "react"; 4 | 5 | import { Button } from "@/components/ui/button"; 6 | import { env } from "@/env"; 7 | import { 8 | useClientTranslation, 9 | useIsAuthed, 10 | useLocaleRouter, 11 | } from "@/hooks/global"; 12 | import { emitter } from "@/lib/mitt"; 13 | import { useAppSession } from "@/stores"; 14 | 15 | const LogOutButton = () => { 16 | const { t } = useClientTranslation(); 17 | const { pushRouter } = useLocaleRouter(); 18 | const updateConfig = useAppSession((state) => state.updateConfig); 19 | const handleLogout = () => { 20 | updateConfig({ apiKey: "", code: "" }); 21 | localStorage.setItem("code", ""); 22 | sessionStorage.setItem("code", ""); 23 | pushRouter(env.NEXT_PUBLIC_AUTH_PATH); 24 | }; 25 | return ; 26 | }; 27 | 28 | const Test = () => { 29 | const { t } = useClientTranslation(); 30 | const isAuthed = useIsAuthed(); 31 | 32 | useEffect(() => { 33 | if (isAuthed) emitter.emit("ToastSuccess", t("land:welcome")); 34 | }, [isAuthed, t]); 35 | 36 | return ( 37 |
38 | {isAuthed && } 39 |
40 | ); 41 | }; 42 | 43 | export default Test; 44 | -------------------------------------------------------------------------------- /src/app/[locale]/(land)/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from "next"; 2 | 3 | import { serverTranslation } from "@/i18n"; 4 | 5 | import LandHeader from "./_components/header"; 6 | import Test from "./_components/test"; 7 | 8 | type Props = { 9 | params: { locale: string }; 10 | searchParams: { [key: string]: string | string[] | undefined }; 11 | }; 12 | 13 | export async function generateMetadata({ params }: Props): Promise { 14 | const locale = params.locale; 15 | const { t } = await serverTranslation(locale); 16 | 17 | return { 18 | title: t("land:title"), 19 | }; 20 | } 21 | 22 | interface pageProps { 23 | params: { 24 | locale: string; 25 | }; 26 | } 27 | 28 | const HomePage = async ({ params: { locale } }: pageProps) => { 29 | const { t } = await serverTranslation(locale); 30 | 31 | return ( 32 |
33 | 34 |

{t("land:desc")}

35 | 36 |
37 | ); 38 | }; 39 | 40 | export default HomePage; 41 | -------------------------------------------------------------------------------- /src/app/[locale]/auth/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from "next"; 2 | 3 | import SignInForm from "@/components/forms/auth"; 4 | import AppLogo from "@/components/global/app-logo"; 5 | import { serverTranslation } from "@/i18n"; 6 | import { Lock } from "@/icons"; 7 | 8 | type Props = { 9 | params: { locale: string }; 10 | searchParams: { [key: string]: string | string[] | undefined }; 11 | }; 12 | 13 | export async function generateMetadata({ params }: Props): Promise { 14 | const locale = params.locale; 15 | const { t } = await serverTranslation(locale); 16 | 17 | return { 18 | title: t("auth:title"), 19 | }; 20 | } 21 | 22 | interface pageProps { 23 | params: { 24 | locale: string; 25 | }; 26 | } 27 | 28 | const AuthPage = async ({ params: { locale } }: pageProps) => { 29 | const { t } = await serverTranslation(locale); 30 | 31 | return ( 32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 |

{t("auth:title")}

41 |

{t("auth:desc")}

42 |
43 | 44 |
45 |
46 |
47 | ); 48 | }; 49 | 50 | export default AuthPage; 51 | -------------------------------------------------------------------------------- /src/app/[locale]/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from "next"; 2 | import dynamic from "next/dynamic"; 3 | import { Inter } from "next/font/google"; 4 | 5 | import AppFooter from "@/components/global/app-footer"; 6 | import AppMessage from "@/components/global/app-message"; 7 | import AppNavbar from "@/components/global/app-navbar"; 8 | import AppQeury from "@/components/global/app-query"; 9 | import AppTheme from "@/components/global/app-theme"; 10 | import { serverTranslation } from "@/i18n"; 11 | import { cn } from "@/lib/utils"; 12 | import "@/styles/globals.css"; 13 | 14 | const AppAuth = dynamic(() => import("@/components/global/app-auth"), { 15 | ssr: false, 16 | }); 17 | const AppChat = dynamic(() => import("@/components/global/app-chat"), { 18 | ssr: false, 19 | }); 20 | 21 | const inter = Inter({ subsets: ["latin"] }); 22 | 23 | type Props = { 24 | params: { locale: string }; 25 | searchParams: { [key: string]: string | string[] | undefined }; 26 | }; 27 | 28 | export async function generateMetadata({ params }: Props): Promise { 29 | const locale = params.locale; 30 | const { t } = await serverTranslation(locale); 31 | 32 | return { 33 | title: { 34 | template: `%s - ${t("global:title")}`, 35 | default: t("global:title"), 36 | }, 37 | description: t("global:desc"), 38 | }; 39 | } 40 | 41 | const RootLayout = ({ 42 | children, 43 | params: { locale }, 44 | }: Readonly<{ 45 | children: React.ReactNode; 46 | params: { locale: string }; 47 | }>) => { 48 | return ( 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
{children}
57 | 58 |
59 |
60 | 61 | 62 | 63 | 64 | ); 65 | }; 66 | 67 | export default RootLayout; 68 | -------------------------------------------------------------------------------- /src/app/[locale]/loading.tsx: -------------------------------------------------------------------------------- 1 | import { DotLoader } from "@/components/common/loader-renderer"; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/components/common/form-generator/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { ErrorMessage } from "@hookform/error-message"; 3 | import { 4 | FieldErrors, 5 | FieldValues, 6 | UseFormRegister, 7 | UseFormSetValue, 8 | } from "react-hook-form"; 9 | 10 | import { Checkbox } from "@/components/ui/checkbox"; 11 | import { Input } from "@/components/ui/input"; 12 | import { Label } from "@/components/ui/label"; 13 | import { Textarea } from "@/components/ui/textarea"; 14 | import { useClientTranslation } from "@/hooks/global"; 15 | import { cn } from "@/lib/utils"; 16 | 17 | import TransRenderer from "../trans-renderer"; 18 | 19 | type FormGeneratorProps = { 20 | inputType: "select" | "input" | "textarea" | "checkbox"; 21 | name: string; 22 | errors: FieldErrors; 23 | type?: "text" | "email" | "password" | "number" | "checkbox"; 24 | options?: { value: string; label: string; id: string }[]; 25 | placeholder?: string; 26 | label?: string; 27 | lines?: number; 28 | register: UseFormRegister; 29 | setValue: UseFormSetValue; 30 | watch: (name: string, defaultValue: any) => any; 31 | className?: string; 32 | }; 33 | 34 | const FormGenerator = ({ 35 | inputType, 36 | options, 37 | label, 38 | placeholder, 39 | register, 40 | setValue, 41 | name, 42 | errors, 43 | type = "text", 44 | lines, 45 | watch, 46 | className, 47 | }: FormGeneratorProps) => { 48 | const { t } = useClientTranslation(); 49 | const renderErrorMessage = () => ( 50 | 54 | message !== "Required" && ( 55 |

56 | 57 |

58 | ) 59 | } 60 | /> 61 | ); 62 | 63 | const renderInput = () => ( 64 | 81 | ); 82 | 83 | const renderSelect = () => ( 84 | 103 | ); 104 | 105 | const renderTextarea = () => ( 106 |