From 2db3868fcf22038a0eac564eab5f04a9f7ac5192 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Fri, 23 Jan 2026 02:35:52 +0800 Subject: [PATCH] update --- .env.example | 3 +- .gitignore | 7 + next.config.ts | 4 + package.json | 27 +- pnpm-lock.yaml | 388 +++++++++++----- public/panda.jpg | Bin 0 -> 44936 bytes src/app/about/page.tsx | 9 - src/app/apps/app/AIEditorLink.tsx | 47 ++ src/app/apps/app/page.tsx | 378 ++++++++++++++++ src/app/apps/constants.ts | 11 + src/app/apps/layouts/index.tsx | 7 + src/app/apps/modules/AppDeleteModal.tsx | 86 ++++ src/app/apps/modules/DatePicker.tsx | 61 +++ src/app/apps/modules/FileUpload.tsx | 111 +++++ src/app/apps/modules/PermissionManager.tsx | 149 +++++++ src/app/apps/modules/TagsInput.tsx | 62 +++ src/app/apps/modules/key-parse.ts | 109 +++++ src/app/apps/page.tsx | 494 +++++++++++++++++++++ src/app/apps/store/app-version.ts | 152 +++++++ src/app/apps/store/index.ts | 2 + src/app/apps/store/user-app.ts | 101 +++++ src/app/domain/page.tsx | 205 +++++++++ src/app/domain/store/index .ts | 92 ++++ src/app/globals.css | 39 ++ src/app/page.tsx | 10 +- src/assets/panda.jpg | Bin 0 -> 44936 bytes src/assets/qrcode-8x8.jpg | Bin 0 -> 27295 bytes src/components/ui/calendar.tsx | 220 +++++++++ src/components/ui/switch.tsx | 31 ++ src/components/ui/table.tsx | 99 +++++ src/components/ui/textarea.tsx | 19 + src/modules/basename.ts | 16 +- src/modules/is-null.ts | 9 + src/modules/layout/LayoutUser.tsx | 178 ++++++++ src/modules/layout/Menu.tsx | 104 +++++ src/modules/layout/index.tsx | 147 ++++++ src/modules/layout/store/index.ts | 104 +++++ src/modules/query.ts | 32 ++ tsconfig.json | 32 +- 39 files changed, 3381 insertions(+), 164 deletions(-) create mode 100644 .gitignore create mode 100644 public/panda.jpg delete mode 100644 src/app/about/page.tsx create mode 100644 src/app/apps/app/AIEditorLink.tsx create mode 100644 src/app/apps/app/page.tsx create mode 100644 src/app/apps/constants.ts create mode 100644 src/app/apps/layouts/index.tsx create mode 100644 src/app/apps/modules/AppDeleteModal.tsx create mode 100644 src/app/apps/modules/DatePicker.tsx create mode 100644 src/app/apps/modules/FileUpload.tsx create mode 100644 src/app/apps/modules/PermissionManager.tsx create mode 100644 src/app/apps/modules/TagsInput.tsx create mode 100644 src/app/apps/modules/key-parse.ts create mode 100644 src/app/apps/page.tsx create mode 100644 src/app/apps/store/app-version.ts create mode 100644 src/app/apps/store/index.ts create mode 100644 src/app/apps/store/user-app.ts create mode 100644 src/app/domain/page.tsx create mode 100644 src/app/domain/store/index .ts create mode 100644 src/assets/panda.jpg create mode 100644 src/assets/qrcode-8x8.jpg create mode 100644 src/components/ui/calendar.tsx create mode 100644 src/components/ui/switch.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/modules/is-null.ts create mode 100644 src/modules/layout/LayoutUser.tsx create mode 100644 src/modules/layout/Menu.tsx create mode 100644 src/modules/layout/index.tsx create mode 100644 src/modules/layout/store/index.ts create mode 100644 src/modules/query.ts diff --git a/.env.example b/.env.example index bc9086d..df7acb0 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ -NODE_ENV= \ No newline at end of file +NODE_ENV= +API_URL=https://kevisual.xiongxiao.me \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..501a050 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules + +.env +!.env*example +dist +.next +out \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index bd40853..c310583 100644 --- a/next.config.ts +++ b/next.config.ts @@ -10,6 +10,10 @@ const nextConfig: NextConfig = { distDir: 'dist', basePath: basePath, trailingSlash: true, + transpilePackages: ['@kevisual/api'], + images: { + unoptimized: true, + }, }; export default nextConfig; diff --git a/package.json b/package.json index 55abc2a..e9b5a1b 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,20 @@ { - "name": "@kevisual/next-simple-template", + "name": "@kevisual/center", "version": "0.1.0", - "basename": "/root/next-simple-template", + "basename": "/root/center", "scripts": { "dev": "next dev", "build": "next build", "start": "next start", - "pub": "ev deploy ./dist -k next-simple-template -v 0.1.0 -u -y y", + "pub": "ev deploy ./dist -k center -v 0.1.0 -u -y y", "ui": "pnpm dlx shadcn@latest add " }, "dependencies": { - "@kevisual/query": "^0.0.35", - "@kevisual/router": "^0.0.53", + "@ant-design/icons": "^6.1.0", + "@kevisual/api": "^0.0.26", + "@kevisual/cache": "^0.0.5", + "@kevisual/query": "^0.0.38", + "@kevisual/router": "^0.0.60", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", @@ -20,25 +23,33 @@ "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", - "antd": "^6.2.0", + "antd": "^6.2.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", + "copy-to-clipboard": "^3.3.3", + "date-fns": "^4.1.0", + "dayjs": "^1.11.19", "dotenv": "^17.2.3", - "es-toolkit": "^1.43.0", + "es-toolkit": "^1.44.0", "idb-keyval": "^6.2.2", "lucide-react": "^0.562.0", - "next": "16.1.2", + "marked": "^17.0.1", + "next": "16.1.4", "react": "19.2.3", + "react-day-picker": "^9.13.0", "react-dom": "19.2.3", + "react-hook-form": "^7.71.1", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "valtio": "^2.3.0", "zustand": "^5.0.10" }, "devDependencies": { + "@kevisual/types": "^0.0.12", "@tailwindcss/postcss": "^4", "@types/node": "^25", "@types/react": "^19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1414a97..f099063 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,21 @@ importers: .: dependencies: + '@ant-design/icons': + specifier: ^6.1.0 + version: 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@kevisual/api': + specifier: ^0.0.26 + version: 0.0.26 + '@kevisual/cache': + specifier: ^0.0.5 + version: 0.0.5 '@kevisual/query': - specifier: ^0.0.35 - version: 0.0.35 + specifier: ^0.0.38 + version: 0.0.38 '@kevisual/router': - specifier: ^0.0.53 - version: 0.0.53 + specifier: ^0.0.60 + version: 0.0.60 '@radix-ui/react-checkbox': specifier: ^1.3.3 version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -38,6 +47,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.2.4 version: 1.2.4(@types/react@19.2.7)(react@19.2.3) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-tabs': specifier: ^1.1.13 version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -45,8 +57,8 @@ importers: specifier: ^1.2.8 version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) antd: - specifier: ^6.2.0 - version: 6.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^6.2.1 + version: 6.2.1(date-fns@4.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -56,30 +68,45 @@ importers: cmdk: specifier: ^1.1.1 version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + copy-to-clipboard: + specifier: ^3.3.3 + version: 3.3.3 + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + dayjs: + specifier: ^1.11.19 + version: 1.11.19 dotenv: specifier: ^17.2.3 version: 17.2.3 es-toolkit: - specifier: ^1.43.0 - version: 1.43.0 + specifier: ^1.44.0 + version: 1.44.0 idb-keyval: specifier: ^6.2.2 version: 6.2.2 - jotai: - specifier: ^2.16.1 - version: 2.16.1(@types/react@19.2.7)(react@19.2.3) lucide-react: specifier: ^0.562.0 version: 0.562.0(react@19.2.3) + marked: + specifier: ^17.0.1 + version: 17.0.1 next: - specifier: 16.1.1 - version: 16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: 16.1.4 + version: 16.1.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: specifier: 19.2.3 version: 19.2.3 + react-day-picker: + specifier: ^9.13.0 + version: 9.13.0(react@19.2.3) react-dom: specifier: 19.2.3 version: 19.2.3(react@19.2.3) + react-hook-form: + specifier: ^7.71.1 + version: 7.71.1(react@19.2.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -93,6 +120,9 @@ importers: specifier: ^5.0.10 version: 5.0.10(@types/react@19.2.7)(react@19.2.3) devDependencies: + '@kevisual/types': + specifier: ^0.0.12 + version: 0.0.12 '@tailwindcss/postcss': specifier: ^4 version: 4.1.18 @@ -130,8 +160,8 @@ packages: react: '>=18' react-dom: '>=18' - '@ant-design/cssinjs@2.0.2': - resolution: {integrity: sha512-7KDVIigtqlamOLtJ0hbjECX/sDGDaJXsM/KHala8I/1E4lpl9RAO585kbVvh/k1rIrFAV6JeGkXmdWyYj9XvuA==} + '@ant-design/cssinjs@2.0.3': + resolution: {integrity: sha512-HAo8SZ3a6G8v6jT0suCz1270na6EA3obeJWM4uzRijBhdwdoMAXWK2f4WWkwB28yUufsfk3CAhN1coGPQq4kNQ==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' @@ -160,6 +190,9 @@ packages: resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} + '@date-fns/tz@1.4.1': + resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} @@ -337,59 +370,74 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@kevisual/query@0.0.35': - resolution: {integrity: sha512-80dyy2LMCmEC72g+X4QWUKlZErhawQPgnGSBNR4yhrBcFgHIJQ14LR1Z+bS5S1I7db+1PDNpaxBTjIaoYoXunw==} + '@kevisual/api@0.0.26': + resolution: {integrity: sha512-u40PNMeVoWfUrUXWSEOc6/aacmt+flq7gE6kdmJJpgc9rfn8I6mXWlp3z0FPrAuqJopKAraiU9To+U72TL8U9g==} - '@kevisual/router@0.0.53': - resolution: {integrity: sha512-Bw9xYVWyxRhd230nF1ac7cyvzWDYKI/3V+Fr1Ew1Bfr0Ey8KuWb1MgPPopHkRHCCcUcysLtWXfu/JRiTAoBmGA==} + '@kevisual/cache@0.0.5': + resolution: {integrity: sha512-fgtUYGUUq/DY0KFV4CkWszNqvQUaA8XvMTUjoR9ZXRpau5IIDolD/Wen2TFsZ7G3Rfy+lef5dnaiZVDkZwdVKg==} - '@next/env@16.1.1': - resolution: {integrity: sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==} + '@kevisual/js-filter@0.0.5': + resolution: {integrity: sha512-+S+Sf3K/aP6XtZI2s7TgKOr35UuvUvtpJ9YDW30a+mY0/N8gRuzyKhieBzQN7Ykayzz70uoMavBXut2rUlLgzw==} - '@next/swc-darwin-arm64@16.1.1': - resolution: {integrity: sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==} + '@kevisual/load@0.0.6': + resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==} + + '@kevisual/query@0.0.38': + resolution: {integrity: sha512-bfvbSodsZyMfwY+1T2SvDeOCKsT/AaIxlVe0+B1R/fNhlg2MDq2CP0L9HKiFkEm+OXrvXcYDMKPUituVUM5J6Q==} + + '@kevisual/router@0.0.60': + resolution: {integrity: sha512-2v/ZzUstsaq+Uqo+tZX9ys5E+/2erPggCtljv9jTb3NA88ZdHsYUAsd5wUFvLtf9QucpJCzyWEt+InDV/98FKw==} + + '@kevisual/types@0.0.12': + resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==} + + '@next/env@16.1.4': + resolution: {integrity: sha512-gkrXnZyxPUy0Gg6SrPQPccbNVLSP3vmW8LU5dwEttEEC1RwDivk8w4O+sZIjFvPrSICXyhQDCG+y3VmjlJf+9A==} + + '@next/swc-darwin-arm64@16.1.4': + resolution: {integrity: sha512-T8atLKuvk13XQUdVLCv1ZzMPgLPW0+DWWbHSQXs0/3TjPrKNxTmUIhOEaoEyl3Z82k8h/gEtqyuoZGv6+Ugawg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.1': - resolution: {integrity: sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==} + '@next/swc-darwin-x64@16.1.4': + resolution: {integrity: sha512-AKC/qVjUGUQDSPI6gESTx0xOnOPQ5gttogNS3o6bA83yiaSZJek0Am5yXy82F1KcZCx3DdOwdGPZpQCluonuxg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.1': - resolution: {integrity: sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==} + '@next/swc-linux-arm64-gnu@16.1.4': + resolution: {integrity: sha512-POQ65+pnYOkZNdngWfMEt7r53bzWiKkVNbjpmCt1Zb3V6lxJNXSsjwRuTQ8P/kguxDC8LRkqaL3vvsFrce4dMQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@16.1.1': - resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==} + '@next/swc-linux-arm64-musl@16.1.4': + resolution: {integrity: sha512-3Wm0zGYVCs6qDFAiSSDL+Z+r46EdtCv/2l+UlIdMbAq9hPJBvGu/rZOeuvCaIUjbArkmXac8HnTyQPJFzFWA0Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@16.1.1': - resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==} + '@next/swc-linux-x64-gnu@16.1.4': + resolution: {integrity: sha512-lWAYAezFinaJiD5Gv8HDidtsZdT3CDaCeqoPoJjeB57OqzvMajpIhlZFce5sCAH6VuX4mdkxCRqecCJFwfm2nQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@16.1.1': - resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==} + '@next/swc-linux-x64-musl@16.1.4': + resolution: {integrity: sha512-fHaIpT7x4gA6VQbdEpYUXRGyge/YbRrkG6DXM60XiBqDM2g2NcrsQaIuj375egnGFkJow4RHacgBOEsHfGbiUw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@16.1.1': - resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==} + '@next/swc-win32-arm64-msvc@16.1.4': + resolution: {integrity: sha512-MCrXxrTSE7jPN1NyXJr39E+aNFBrQZtO154LoCz7n99FuKqJDekgxipoodLNWdQP7/DZ5tKMc/efybx1l159hw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.1': - resolution: {integrity: sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==} + '@next/swc-win32-x64-msvc@16.1.4': + resolution: {integrity: sha512-JSVlm9MDhmTXw/sO2PE/MRj+G6XOSMZB+BcZ0a7d6KwVFZVpkHcb2okyoYFBaco6LeiL53BBklRlOrDDbOeE5w==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -697,6 +745,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-tabs@1.1.13': resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} peerDependencies: @@ -983,8 +1044,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/resize-observer@1.0.1': - resolution: {integrity: sha512-r+w+Mz1EiueGk1IgjB3ptNXLYSLZ5vnEfKHH+gfgj7JMupftyzvUUl3fRcMZe5uMM04x0n8+G2o/c6nlO2+Wag==} + '@rc-component/resize-observer@1.1.1': + resolution: {integrity: sha512-NfXXMmiR+SmUuKE1NwJESzEUYUFWIDUn2uXpxCTOLwiRUUakd62DRNFjRJArgzyFW8S5rsL4aX5XlyIXyC/vRA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1068,8 +1129,8 @@ packages: react: '*' react-dom: '*' - '@rc-component/trigger@3.8.2': - resolution: {integrity: sha512-I6idYAk8YY3Ly6v5hB7ONqxfdTYTcVNUmV1ZjtSsGH6N/k5tss9+OAtusr+7zdlIcD7TwnlsoB5etfB14ORtMw==} + '@rc-component/trigger@3.9.0': + resolution: {integrity: sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg==} engines: {node: '>=8.x'} peerDependencies: react: '>=18.0.0' @@ -1196,8 +1257,8 @@ packages: '@types/react@19.2.7': resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} - antd@6.2.0: - resolution: {integrity: sha512-fwETatwHYExjfzKcV41fBtgPo4kp+g+9gp5YOSSGxwnJHljps8TbXef8WP7ZnaOn5dkcA9xIC0TyUecIybBG7w==} + antd@6.2.1: + resolution: {integrity: sha512-ycw/XX7So4MdrwYKGfvZJdkGiCYUOSTebAIi+ejE95WJ138b11oy/iJg7iH0qydaD/B5sFd7Tz8XfPBuW7CRmw==} peerDependencies: react: '>=18.0.0' react-dom: '>=18.0.0' @@ -1232,9 +1293,18 @@ packages: compute-scroll-into-view@3.1.1: resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + date-fns-jalali@4.1.0-0: + resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + dayjs@1.11.19: resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} @@ -1253,8 +1323,11 @@ packages: resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} - es-toolkit@1.43.0: - resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} + es-toolkit@1.44.0: + resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} @@ -1263,6 +1336,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hono@4.11.5: + resolution: {integrity: sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g==} + engines: {node: '>=16.9.0'} + idb-keyval@6.2.2: resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} @@ -1273,24 +1350,6 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jotai@2.16.1: - resolution: {integrity: sha512-vrHcAbo3P7Br37C8Bv6JshMtlKMPqqmx0DDREtTjT4nf3QChDrYdbH+4ik/9V0cXA57dK28RkJ5dctYvavcIlg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@babel/core': '>=7.0.0' - '@babel/template': '>=7.0.0' - '@types/react': '>=17.0.0' - react: '>=17.0.0' - peerDependenciesMeta: - '@babel/core': - optional: true - '@babel/template': - optional: true - '@types/react': - optional: true - react: - optional: true - json2mq@0.2.0: resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} @@ -1364,6 +1423,10 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + lucide-react@0.562.0: resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} peerDependencies: @@ -1372,13 +1435,23 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + marked@17.0.1: + resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} + engines: {node: '>= 20'} + hasBin: true + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - next@16.1.1: - resolution: {integrity: sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==} + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + engines: {node: ^18 || >=20} + hasBin: true + + next@16.1.4: + resolution: {integrity: sha512-gKSecROqisnV7Buen5BfjmXAm7Xlpx9o2ueVQRo5DxQcjC8d330dOM1xiGWc2k3Dcnz0In3VybyRPOsudwgiqQ==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -1412,11 +1485,23 @@ packages: proxy-compare@3.0.1: resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + react-day-picker@9.13.0: + resolution: {integrity: sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==} + engines: {node: '>=18'} + peerDependencies: + react: '>=16.8.0' + react-dom@19.2.3: resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} peerDependencies: react: ^19.2.3 + react-hook-form@7.71.1: + resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -1512,6 +1597,9 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1586,13 +1674,13 @@ snapshots: '@ant-design/cssinjs-utils@2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@ant-design/cssinjs': 2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs': 2.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@babel/runtime': 7.28.6 '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@ant-design/cssinjs@2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@ant-design/cssinjs@2.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@babel/runtime': 7.28.6 '@emotion/hash': 0.8.0 @@ -1628,6 +1716,8 @@ snapshots: '@babel/runtime@7.28.6': {} + '@date-fns/tz@1.4.1': {} + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 @@ -1770,36 +1860,60 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kevisual/query@0.0.35': + '@kevisual/api@0.0.26': + dependencies: + '@kevisual/js-filter': 0.0.5 + '@kevisual/load': 0.0.6 + es-toolkit: 1.44.0 + eventemitter3: 5.0.4 + nanoid: 5.1.6 + + '@kevisual/cache@0.0.5': + dependencies: + idb-keyval: 6.2.2 + lru-cache: 11.2.4 + nanoid: 5.1.6 + + '@kevisual/js-filter@0.0.5': {} + + '@kevisual/load@0.0.6': + dependencies: + eventemitter3: 5.0.4 + + '@kevisual/query@0.0.38': dependencies: tslib: 2.8.1 - '@kevisual/router@0.0.53': {} + '@kevisual/router@0.0.60': + dependencies: + hono: 4.11.5 - '@next/env@16.1.1': {} + '@kevisual/types@0.0.12': {} - '@next/swc-darwin-arm64@16.1.1': + '@next/env@16.1.4': {} + + '@next/swc-darwin-arm64@16.1.4': optional: true - '@next/swc-darwin-x64@16.1.1': + '@next/swc-darwin-x64@16.1.4': optional: true - '@next/swc-linux-arm64-gnu@16.1.1': + '@next/swc-linux-arm64-gnu@16.1.4': optional: true - '@next/swc-linux-arm64-musl@16.1.1': + '@next/swc-linux-arm64-musl@16.1.4': optional: true - '@next/swc-linux-x64-gnu@16.1.1': + '@next/swc-linux-x64-gnu@16.1.4': optional: true - '@next/swc-linux-x64-musl@16.1.1': + '@next/swc-linux-x64-musl@16.1.4': optional: true - '@next/swc-win32-arm64-msvc@16.1.1': + '@next/swc-win32-arm64-msvc@16.1.4': optional: true - '@next/swc-win32-x64-msvc@16.1.1': + '@next/swc-win32-x64-msvc@16.1.4': optional: true '@radix-ui/number@1.1.1': {} @@ -2127,6 +2241,21 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.3) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.3) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -2291,7 +2420,7 @@ snapshots: '@rc-component/dropdown@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2334,7 +2463,7 @@ snapshots: '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/textarea': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2344,7 +2473,7 @@ snapshots: dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2378,7 +2507,7 @@ snapshots: '@rc-component/overflow@1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@babel/runtime': 7.28.6 - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2391,16 +2520,17 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/picker@1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/picker@1.9.0(date-fns@4.1.0)(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) optionalDependencies: + date-fns: 4.1.0 dayjs: 1.11.19 '@rc-component/portal@2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': @@ -2430,7 +2560,7 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/resize-observer@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/resize-observer@1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -2448,7 +2578,7 @@ snapshots: '@rc-component/select@1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 @@ -2479,7 +2609,7 @@ snapshots: '@rc-component/table@1.9.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/context': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 @@ -2491,7 +2621,7 @@ snapshots: '@rc-component/dropdown': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2500,7 +2630,7 @@ snapshots: '@rc-component/textarea@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2508,7 +2638,7 @@ snapshots: '@rc-component/tooltip@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2517,7 +2647,7 @@ snapshots: '@rc-component/tour@2.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2541,11 +2671,11 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/trigger@3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/trigger@3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2568,7 +2698,7 @@ snapshots: '@rc-component/virtual-list@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@babel/runtime': 7.28.6 - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -2659,10 +2789,10 @@ snapshots: dependencies: csstype: 3.2.3 - antd@6.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + antd@6.2.1(date-fns@4.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@ant-design/colors': 8.0.1 - '@ant-design/cssinjs': 2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs': 2.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@ant-design/cssinjs-utils': 2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@ant-design/fast-color': 3.0.0 '@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2685,11 +2815,11 @@ snapshots: '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/notification': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/pagination': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/picker': 1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/picker': 1.9.0(date-fns@4.1.0)(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/progress': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/qrcode': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/segmented': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/select': 1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/slider': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2702,7 +2832,7 @@ snapshots: '@rc-component/tour': 2.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree-select': 1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 @@ -2746,8 +2876,16 @@ snapshots: compute-scroll-into-view@3.1.1: {} + copy-to-clipboard@3.3.3: + dependencies: + toggle-selection: 1.0.6 + csstype@3.2.3: {} + date-fns-jalali@4.1.0-0: {} + + date-fns@4.1.0: {} + dayjs@1.11.19: {} detect-libc@2.1.2: {} @@ -2761,23 +2899,22 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 - es-toolkit@1.43.0: {} + es-toolkit@1.44.0: {} + + eventemitter3@5.0.4: {} get-nonce@1.0.1: {} graceful-fs@4.2.11: {} + hono@4.11.5: {} + idb-keyval@6.2.2: {} is-mobile@5.0.0: {} jiti@2.6.1: {} - jotai@2.16.1(@types/react@19.2.7)(react@19.2.3): - optionalDependencies: - '@types/react': 19.2.7 - react: 19.2.3 - json2mq@0.2.0: dependencies: string-convert: 0.2.1 @@ -2831,6 +2968,8 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lru-cache@11.2.4: {} + lucide-react@0.562.0(react@19.2.3): dependencies: react: 19.2.3 @@ -2839,11 +2978,15 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + marked@17.0.1: {} + nanoid@3.3.11: {} - next@16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + nanoid@5.1.6: {} + + next@16.1.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@next/env': 16.1.1 + '@next/env': 16.1.4 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.9.11 caniuse-lite: 1.0.30001762 @@ -2852,14 +2995,14 @@ snapshots: react-dom: 19.2.3(react@19.2.3) styled-jsx: 5.1.6(react@19.2.3) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.1 - '@next/swc-darwin-x64': 16.1.1 - '@next/swc-linux-arm64-gnu': 16.1.1 - '@next/swc-linux-arm64-musl': 16.1.1 - '@next/swc-linux-x64-gnu': 16.1.1 - '@next/swc-linux-x64-musl': 16.1.1 - '@next/swc-win32-arm64-msvc': 16.1.1 - '@next/swc-win32-x64-msvc': 16.1.1 + '@next/swc-darwin-arm64': 16.1.4 + '@next/swc-darwin-x64': 16.1.4 + '@next/swc-linux-arm64-gnu': 16.1.4 + '@next/swc-linux-arm64-musl': 16.1.4 + '@next/swc-linux-x64-gnu': 16.1.4 + '@next/swc-linux-x64-musl': 16.1.4 + '@next/swc-win32-arm64-msvc': 16.1.4 + '@next/swc-win32-x64-msvc': 16.1.4 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -2881,11 +3024,22 @@ snapshots: proxy-compare@3.0.1: {} + react-day-picker@9.13.0(react@19.2.3): + dependencies: + '@date-fns/tz': 1.4.1 + date-fns: 4.1.0 + date-fns-jalali: 4.1.0-0 + react: 19.2.3 + react-dom@19.2.3(react@19.2.3): dependencies: react: 19.2.3 scheduler: 0.27.0 + react-hook-form@7.71.1(react@19.2.3): + dependencies: + react: 19.2.3 + react-is@18.3.1: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.3): @@ -2982,6 +3136,8 @@ snapshots: throttle-debounce@5.0.2: {} + toggle-selection@1.0.6: {} + tslib@2.8.1: {} tw-animate-css@1.4.0: {} diff --git a/public/panda.jpg b/public/panda.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f1beff098ca25863d7864d20df4fccc5017edbc GIT binary patch literal 44936 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 -

- About Light Code -
- - ); -} \ No newline at end of file diff --git a/src/app/apps/app/AIEditorLink.tsx b/src/app/apps/app/AIEditorLink.tsx new file mode 100644 index 0000000..a759897 --- /dev/null +++ b/src/app/apps/app/AIEditorLink.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { useLayoutStore } from '@/modules/layout/store'; +import { useShallow } from 'zustand/shallow'; +import { toast } from 'sonner'; +import { Folder } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; +import { openLink } from '@/modules/basename'; + +type Props = { + pathname?: string; +}; +export const AIEditorLink = (props: Props) => { + const layoutUser = useLayoutStore( + useShallow((state) => ({ + user: state.me?.username || '', + })), + ); + return ( + + + + + 打开对应的文件夹 + + ); +}; diff --git a/src/app/apps/app/page.tsx b/src/app/apps/app/page.tsx new file mode 100644 index 0000000..39bb2fc --- /dev/null +++ b/src/app/apps/app/page.tsx @@ -0,0 +1,378 @@ +'use client'; + +import { useAppVersionStore } from '../store'; +import { useShallow } from 'zustand/react/shallow'; +import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react'; +import { Plus, ChevronLeft, Upload, File, Trash2, ExternalLink } from 'lucide-react'; +import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; +import { isObjectNull } from '@/modules/is-null'; +import { FileUpload } from '../modules/FileUpload'; +import clsx from 'clsx'; +import { toast as message } from 'sonner'; +import { Button } from '@/components/ui/button'; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Controller, useForm } from 'react-hook-form'; +import { pick } from 'es-toolkit'; +import { useAppDeleteModalStore, AppDeleteModal } from '../modules/AppDeleteModal'; +import { AIEditorLink } from './AIEditorLink'; +import { openLink } from '@/modules/basename'; +import { LayoutMain } from '@/modules/layout'; + +const FormModal = () => { + const { control, handleSubmit, reset } = useForm(); + const containerStore = useAppVersionStore( + useShallow((state) => { + return { + showEdit: state.showEdit, + setShowEdit: state.setShowEdit, + formData: state.formData, + updateData: state.updateData, + }; + }), + ); + + useEffect(() => { + const open = containerStore.showEdit; + if (open) { + const isNull = isObjectNull(containerStore.formData); + if (isNull) { + reset({}); + } else { + reset(containerStore.formData); + } + } + }, [containerStore.showEdit]); + + const onFinish = async (values: any) => { + const pickValues = pick(values, ['id', 'key', 'version']); + containerStore.updateData(pickValues); + }; + + const onClose = () => { + containerStore.setShowEdit(false); + reset(); + }; + + const isEdit = containerStore.formData.id; + + return ( + containerStore.setShowEdit(open)}> + + + {isEdit ? 'Edit' : 'Add'} + +
+
+ + } + /> +
+
+ + } + /> +
+
+ + +
+
+
+
+ ); +}; + +const getAppKey = () => { + const [appKey, setAppKey] = useState(''); + useLayoutEffect(() => { + if (typeof window === 'undefined') return; + const url = new URL(window.location.href); + const appKey = url.searchParams.get('appKey'); + setAppKey(appKey || ''); + }, []); + return appKey || ''; +} +export const AppVersionList = () => { + const appKey = getAppKey(); + const versionStore = useAppVersionStore( + useShallow((state) => { + return { + list: state.list, + getList: state.getList, + key: state.key, + setKey: state.setKey, + setShowEdit: state.setShowEdit, + formData: state.formData, + setFormData: state.setFormData, + deleteData: state.deleteData, + publishVersion: state.publishVersion, + app: state.app, + }; + }), + ); + const appDeleteModalStore = useAppDeleteModalStore( + useShallow((state) => { + return { + onClickDelete: state.onClickDelete, + }; + }), + ); + const [isUpload, setIsUpload] = useState(false); + useEffect(() => { + // fetch app version list + if (appKey) { + versionStore.setKey(appKey); + versionStore.getList(); + } + }, [appKey]); + const appVersion = useMemo(() => { + return versionStore.app?.version || ''; + }, [versionStore.app?.version]); + if (!appKey) { + return
App Key is required
; + } + return ( +
+
+ + + + + 添加版本 + +
+ +
+
+ + + + + 返回 + +
+ +
+
+
+ {versionStore.list.map((item, index) => { + const isPublish = item.version === appVersion; + const color = isPublish ? 'bg-green-500' : ''; + const isRunning = item.status === 'running'; + return ( +
+
+ {item.version} + + + +
+
+ {isPublish ? 'published' : ''} +
+
+
+ + + + + Delete + + + + + + 使用当前版本,发布为此版本 + + + + + + To Test App + + + + + + + 文件管理 + +
+
+ ); + })} +
+
+
+
+
+ {isUpload && ( +
+
+ + + + + 返回 + +
{versionStore.key}
+
+ +
+ )} +
+ + +
+ ); +}; +export const AppVersionFile = () => { + const versionStore = useAppVersionStore( + useShallow((state) => { + return { + formData: state.formData, + detectVersionList: state.detectVersionList, + }; + }), + ); + const versionFiles = useMemo(() => { + if (!versionStore.formData?.data) return []; + const files = versionStore.formData.data.files || []; + return files as any[]; + }, [versionStore.formData]); + const onDetect = useCallback(async () => { + console.log('formData', versionStore.formData); + if (!versionStore.formData.key || !versionStore.formData.version) { + message.error('请先选择应用和版本'); + return; + } + const res = await versionStore.detectVersionList({ + appKey: versionStore.formData.key, + version: versionStore.formData.version, + }); + console.log('res', res); + if (res.code === 200) { + message.success('检测实际文件成功'); + } else { + message.error(res.message || 'Detect failed'); + } + }, [versionStore.formData]); + return ( + <> +
version: {versionStore.formData.version}
+
+
+ Files + + + + + + 从同文件目录下检测已经上传的文件内容 + +
+
+
+ {versionFiles.map((file, index) => { + const prefix = versionStore.formData.key + '/' + versionStore.formData.version + '/'; + const _path = file.path || ''; + const path = _path.replace(prefix, ''); + return ( +
+ {/*
{file.name}
*/} +
+ +
+
{path}
+
+ ); + })} +
+
+
+ + ); +}; + +export default () => { + return + + +}; \ No newline at end of file diff --git a/src/app/apps/constants.ts b/src/app/apps/constants.ts new file mode 100644 index 0000000..db5722a --- /dev/null +++ b/src/app/apps/constants.ts @@ -0,0 +1,11 @@ +export const iText = { + share: { + title: '共享设置', + tips: `共享设置 + + 1. 设置公共可以直接访问 + 2. 设置受保护需要登录后访问 + 3. 设置私有只有自己可以访问。\n + 受保护可以设置密码,设置访问的用户名。切换共享状态后,需要重新设置密码和用户名。`, + }, +}; diff --git a/src/app/apps/layouts/index.tsx b/src/app/apps/layouts/index.tsx new file mode 100644 index 0000000..9851c52 --- /dev/null +++ b/src/app/apps/layouts/index.tsx @@ -0,0 +1,7 @@ +'use client'; + +import { LayoutMain } from '@/modules/layout'; + +export const Main = () => { + return ; +}; diff --git a/src/app/apps/modules/AppDeleteModal.tsx b/src/app/apps/modules/AppDeleteModal.tsx new file mode 100644 index 0000000..baf5bda --- /dev/null +++ b/src/app/apps/modules/AppDeleteModal.tsx @@ -0,0 +1,86 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { useState } from 'react'; +import { create } from 'zustand'; +import { useAppVersionStore, useUserAppStore } from '../store'; +import { useShallow } from 'zustand/shallow'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; + +type AppDeleteModalStore = { + open: boolean; + setOpen: (open: boolean) => void; + app: any; + setApp: (app: any) => void; + type: 'user-app' | 'app-version'; + setType: (type: 'user-app' | 'app-version') => void; + onClickDelete: (type: 'user-app' | 'app-version', data: any) => void; +}; +export const useAppDeleteModalStore = create((set) => ({ + open: false, + setOpen: (open) => set({ open }), + app: null, + setApp: (app) => set({ app }), + type: 'user-app', + setType: (type) => set({ type }), + onClickDelete: (type, data) => { + set({ open: true, type, app: data }); + }, +})); + +export const AppDeleteModal = () => { + const { open, setOpen, app, type } = useAppDeleteModalStore(); + const userAppStore = useUserAppStore( + useShallow((state) => { + return { + deleteData: state.deleteData, + }; + }), + ); + const appVersionStore = useAppVersionStore( + useShallow((state) => { + return { + deleteData: state.deleteData, + }; + }), + ); + const onClose = () => { + setOpen(false); + }; + const onDelete = (deleteFile = false) => { + if (type === 'user-app') { + userAppStore.deleteData(app.id, deleteFile); + } else { + appVersionStore.deleteData(app.id, deleteFile); + } + setOpen(false); + }; + + return ( + + + + Tips + +
+

Delete App Introduce

+
+ + + + + +
+
+ ); +}; diff --git a/src/app/apps/modules/DatePicker.tsx b/src/app/apps/modules/DatePicker.tsx new file mode 100644 index 0000000..84283bd --- /dev/null +++ b/src/app/apps/modules/DatePicker.tsx @@ -0,0 +1,61 @@ +"use client" + +import * as React from "react" +import { Calendar as CalendarIcon } from "lucide-react" +import dayjs, { type Dayjs } from "dayjs" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { Calendar } from "@/components/ui/calendar" +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" + +interface DatePickerProps { + className?: string + value?: string | Dayjs + onChange?: (date: Dayjs) => void +} + +export function DatePicker({ className, value, onChange }: DatePickerProps) { + const [date, setDate] = React.useState( + value ? new Date(typeof value === 'string' ? value : value.toISOString()) : undefined + ) + + React.useEffect(() => { + if (value) { + const dateValue = typeof value === 'string' ? value : value.toISOString() + setDate(new Date(dateValue)) + } + }, [value]) + + const handleSelect = (selectedDate: Date | undefined) => { + setDate(selectedDate) + if (selectedDate && onChange) { + onChange(dayjs(selectedDate)) + } + } + + return ( + + + + + + + + + ) +} diff --git a/src/app/apps/modules/FileUpload.tsx b/src/app/apps/modules/FileUpload.tsx new file mode 100644 index 0000000..ef26dd0 --- /dev/null +++ b/src/app/apps/modules/FileUpload.tsx @@ -0,0 +1,111 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { useCallback, useRef } from 'react'; +import { useAppVersionStore } from '../store'; +import { useShallow } from 'zustand/react/shallow'; +import { toast as message } from 'sonner'; + +export type FileType = { + name: string; + size: number; + lastModified: number; + webkitRelativePath: string; // 包含name +}; + +export const FileUpload = () => { + const ref = useRef(null); + const appVersionStore = useAppVersionStore( + useShallow((state) => { + return { + formData: state.formData, + setFormData: state.setFormData, + updateByFromData: state.updateByFromData, + }; + }), + ); + const onChange = useCallback( + async (e: any) => { + console.log(e.target.files); + // webkitRelativePath + let files = Array.from(e.target.files) as any[]; + console.log(files); + if (files.length === 0) { + message.error('请选择文件'); + return; + } + + // 过滤 文件 .DS_Store + files = files.filter((file) => { + if (file.webkitRelativePath.startsWith('__MACOSX')) { + return false; + } + // 过滤node_modules + if (file.webkitRelativePath.includes('node_modules')) { + return false; + } + // 过滤以.开头的文件 + return !file.name.startsWith('.'); + }); + if (files.length === 0) { + console.log('no files'); + return; + } + const root = files[0].webkitRelativePath.split('/')[0]; + const formData = new FormData(); + files.forEach((file) => { + // relativePath 去除第一级 + const webkitRelativePath = file.webkitRelativePath.replace(root + '/', ''); + formData.append('file', file, webkitRelativePath); // 保留文件夹路径 + }); + const key = appVersionStore.formData.key; + const version = appVersionStore.formData.version; + formData.append('appKey', key); + formData.append('version', version); + const res = await fetch('/api/app/upload', { + method: 'POST', + body: formData, // + headers: { + Authorization: 'Bearer ' + (typeof window !== 'undefined' ? localStorage.getItem('token') : ''), + }, + }).then((res) => res.json()); + if (res?.code === 200) { + appVersionStore.setFormData(res.data); + appVersionStore.updateByFromData(); + } else { + message.error(res.message || 'Request failed'); + } + // 清理之前上传的文件 + e.target.value = ''; + }, + [appVersionStore.formData], + ); + + return ( +
+ + +
+ ); +}; diff --git a/src/app/apps/modules/PermissionManager.tsx b/src/app/apps/modules/PermissionManager.tsx new file mode 100644 index 0000000..6e65d1b --- /dev/null +++ b/src/app/apps/modules/PermissionManager.tsx @@ -0,0 +1,149 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { KeyParse, getTips } from './key-parse'; +import { DatePicker } from './DatePicker'; +import { TagsInput } from './TagsInput'; +import { HelpCircle } from 'lucide-react'; +import clsx from 'clsx'; +import { Button } from '@/components/ui/button'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { Input } from "@/components/ui/input" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" + +export const KeyShareSelect = ({ value, onChange }: { value: string; onChange?: (value: string) => void }) => { + return ( + + ); +}; + +export const KeyTextField = ({ name, value, onChange }: { name: string; value: string; onChange?: (value: string) => void }) => { + return ( + onChange?.(e.target.value)} + className="w-full" + /> + ); +}; + +type PermissionManagerProps = { + value: Record; + onChange: (value: Record) => void; + className?: string; +}; + +export const PermissionManager = ({ value, onChange, className }: PermissionManagerProps) => { + const [formData, setFormData] = useState(value); + const [keys, setKeys] = useState([]); + + useEffect(() => { + const hasShare = value?.share && value?.share === 'protected'; + setFormData(KeyParse.parse(value || {})); + if (hasShare) { + setKeys(['password', 'usernames', 'expiration-time']); + } else { + setKeys([]); + } + }, [value]); + + const onChangeValue = (key: string, newValue: any) => { + let newFormData = { ...formData, [key]: newValue }; + if (key === 'share') { + if (newValue === 'protected') { + newFormData = { ...newFormData, password: '', usernames: [], 'expiration-time': null }; + onChange(KeyParse.stringify(newFormData)); + setKeys(['password', 'usernames', 'expiration-time']); + } else { + delete newFormData.password; + delete newFormData.usernames; + delete newFormData['expiration-time']; + onChange(KeyParse.stringify(newFormData)); + setKeys([]); + } + } else { + onChange(KeyParse.stringify(newFormData)); + } + }; + + const tips = getTips('share'); + + return ( + +
+
+
+ + {tips && ( + + + + + +

{tips}

+
+
+ )} +
+ onChangeValue('share', value)} /> +
+ + {keys.map((item: any) => { + const tips = getTips(item); + + return ( +
+
+ + {tips && ( + + + + + +

{tips}

+
+
+ )} +
+ {item === 'expiration-time' && ( + onChangeValue(item, date)} /> + )} + {item === 'usernames' && ( + onChangeValue(item, value)} /> + )} + {item !== 'expiration-time' && item !== 'usernames' && ( + onChangeValue(item, value)} /> + )} +
+ ); + })} +
+
+ ); +}; diff --git a/src/app/apps/modules/TagsInput.tsx b/src/app/apps/modules/TagsInput.tsx new file mode 100644 index 0000000..6d6aae1 --- /dev/null +++ b/src/app/apps/modules/TagsInput.tsx @@ -0,0 +1,62 @@ +"use client" + +import * as React from "react" +import { X } from "lucide-react" +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" + +type TagsInputProps = { + value: string[]; + onChange: (value: string[]) => void; + placeholder?: string; + className?: string; +}; + +export function TagsInput({ value, onChange, placeholder = "输入用户名,按回车添加", className }: TagsInputProps) { + const [inputValue, setInputValue] = React.useState("") + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === ",") { + e.preventDefault() + const newValue = inputValue.trim() + if (newValue && !value.includes(newValue)) { + onChange([...value, newValue]) + } + setInputValue("") + } else if (e.key === "Backspace" && !inputValue && value.length > 0) { + onChange(value.slice(0, -1)) + } + } + + const removeTag = (tagToRemove: string) => { + onChange(value.filter((tag) => tag !== tagToRemove)) + } + + return ( +
+ {value.map((tag, index) => ( +
+ {tag} + +
+ ))} + setInputValue(e.target.value)} + onKeyDown={handleKeyDown} + placeholder={value.length === 0 ? placeholder : ""} + className="flex-1 min-w-[120px] h-8" + /> +
+ ) +} diff --git a/src/app/apps/modules/key-parse.ts b/src/app/apps/modules/key-parse.ts new file mode 100644 index 0000000..cdd573c --- /dev/null +++ b/src/app/apps/modules/key-parse.ts @@ -0,0 +1,109 @@ +'use client'; + +import dayjs from 'dayjs'; +export const getTips = (key: string, lang?: string) => { + const tip = keysTips.find((item) => item.key === key); + if (tip) { + if (lang === 'en') { + return tip.enTips; + } + return tip.tips; + } + return ''; +}; +export const keysTips = [ + { + key: 'share', + tips: `共享设置 + 1. 设置公共可以直接访问 + 2. 设置受保护需要登录后访问 + 3. 设置私有只有自己可以访问。\n + 受保护可以设置密码,设置访问的用户名。切换共享状态后,需要重新设置密码和用户名。 不设置,默认是只能自己访问。`, + enTips: `1. Set public to directly access + 2. Set protected to access after login + 3. Set private to access only yourself. + Protected can set a password and set the username for access. After switching the shared state, you need to reset the password and username. If not set, it defaults to only being accessible to yourself.`, + }, + { + key: 'content-type', + tips: `内容类型,设置文件的内容类型。默认不要修改。`, + enTips: `Content type, set the content type of the file. Default do not modify.`, + }, + { + key: 'app-source', + tips: `应用来源,上传方式。默认不要修改。`, + enTips: `App source, upload method. Default do not modify.`, + }, + { + key: 'cache-control', + tips: `缓存控制,设置文件的缓存控制。默认不要修改。`, + enTips: `Cache control, set the cache control of the file. Default do not modify.`, + }, + { + key: 'password', + tips: `密码,设置文件的密码。不设置默认是所有人都可以访问。`, + enTips: `Password, set the password of the file. If not set, it defaults to everyone can access.`, + }, + { + key: 'usernames', + tips: `用户名,设置文件的用户名。不设置默认是所有人都可以访问。`, + enTips: `Username, set the username of the file. If not set, it defaults to everyone can access.`, + parse: (value: string) => { + if (!value) { + return []; + } + return value.split(','); + }, + stringify: (value: string[]) => { + if (!value) { + return ''; + } + return value.join(','); + }, + }, + { + key: 'expiration-time', + tips: `过期时间,设置文件的过期时间。不设置默认是永久。`, + enTips: `Expiration time, set the expiration time of the file. If not set, it defaults to permanent.`, + parse: (value: Date) => { + if (!value) { + return null; + } + return dayjs(value); + }, + stringify: (value?: dayjs.Dayjs) => { + if (!value) { + return ''; + } + return value.toISOString(); + }, + }, +]; +export class KeyParse { + static parse(metadata: Record) { + const keys = Object.keys(metadata); + const newMetadata = {}; + keys.forEach((key) => { + const tip = keysTips.find((item) => item.key === key); + if (tip && tip.parse) { + newMetadata[key] = tip.parse(metadata[key]); + } else { + newMetadata[key] = metadata[key]; + } + }); + return newMetadata; + } + static stringify(metadata: Record) { + const keys = Object.keys(metadata); + const newMetadata = {}; + keys.forEach((key) => { + const tip = keysTips.find((item) => item.key === key); + if (tip && tip.stringify) { + newMetadata[key] = tip.stringify(metadata[key]); + } else { + newMetadata[key] = metadata[key]; + } + }); + return newMetadata; + } +} diff --git a/src/app/apps/page.tsx b/src/app/apps/page.tsx new file mode 100644 index 0000000..67aeea7 --- /dev/null +++ b/src/app/apps/page.tsx @@ -0,0 +1,494 @@ +'use client'; + +import { useShallow } from 'zustand/react/shallow'; +import { useAppVersionStore, useUserAppStore } from './store'; +import { useEffect, useMemo, useState } from 'react'; +// import { useModal } from '@kevisual/components/modal/Confirm.tsx'; + +import { Plus, Code, Link as LinkIcon, Edit, Trash2, Share2, RefreshCcw, ExternalLink, Folder } from 'lucide-react'; +import { isObjectNull } from '@/modules/is-null'; +import clsx from 'clsx'; +// import { IconButton } from '@kevisual/components/button/index.tsx'; +// import { Select } from '@kevisual/components/select/index.tsx'; +import { iText } from './constants'; +import { PermissionManager } from './modules/PermissionManager'; +import { toast as message } from 'sonner'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Button } from '@/components/ui/button'; +import { Textarea } from '@/components/ui/textarea'; +import { Controller, useForm } from 'react-hook-form'; +import { pick } from 'es-toolkit'; +import copy from 'copy-to-clipboard'; +import { useLayoutStore } from '@/modules/layout/store'; +import { useAppDeleteModalStore, AppDeleteModal } from './modules/AppDeleteModal'; +import { AppWindow, Folder as FolderIcon } from 'lucide-react'; +import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; +import { Switch } from '@/components/ui/switch'; +import { AIEditorLink } from './app/AIEditorLink'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { LayoutMain } from '@/modules/layout'; +import { openLink } from '@/modules/basename'; +export const IconButton = (props: any) => { + return ( + + ); +}; +const FormModal = () => { + const defaultValues = { + id: '', + title: '', + domain: '', + key: '', + description: '', + proxy: true, + status: 'running', + }; + const { control, handleSubmit, reset } = useForm({ + defaultValues, + }); + const containerStore = useUserAppStore( + useShallow((state) => { + return { + showEdit: state.showEdit, + setShowEdit: state.setShowEdit, + userApp: state.userApp, + updateData: state.updateData, + }; + }), + ); + useEffect(() => { + const open = containerStore.showEdit; + if (open) { + const isNull = isObjectNull(containerStore.userApp); + if (isNull) { + reset(defaultValues); + } else { + reset(containerStore.userApp); + } + } + }, [containerStore.showEdit, containerStore.userApp]); + const onFinish = async (values: any) => { + const pickValues = pick(values, ['id', 'title', 'domain', 'key', 'description', 'proxy', 'status']); + containerStore.updateData(pickValues); + }; + const onClose = () => { + containerStore.setShowEdit(false); + reset(); + }; + const isEdit = containerStore?.userApp?.id; + const isAdmin = useLayoutStore(useShallow((state) => state.isAdmin)); + + return ( + containerStore.setShowEdit(open)}> + + + {isEdit ? '编辑' : '添加'} + +
+
+ + } /> +
+
+ + } /> +
+
+ +