♻️ refactor(core): Restructure project for better module separation

This commit is contained in:
web@ppanel 2024-12-26 02:53:28 +07:00
parent 17ce96a423
commit 9d0cb8b869
368 changed files with 152606 additions and 47239 deletions

View File

@ -1,3 +0,0 @@
module.exports = {
extends: ['@repo/commitlint-config'],
};

View File

@ -0,0 +1,89 @@
name: Publish Release Assets
on:
release:
types: [published]
permissions:
contents: write
jobs:
publish:
name: Publish Release Assets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 'latest'
- name: Cache Bun dependencies
uses: actions/cache@v3
with:
path: |
~/.bun
key: ${{ runner.os }}-bun-cache-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-cache-
- name: Install deps
run: bun install --cache
- name: Build
run: bun run build
- name: Run publish script
run: |
chmod +x scripts/publish.sh
./scripts/publish.sh
- name: Upload tar.gz file to release
uses: softprops/action-gh-release@v2
with:
files: |
out/ppanel-admin-web.tar.gz
out/ppanel-user-web.tar.gz
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Install jq
run: sudo apt-get install -y jq
- name: Extract version from package.json
id: version
run: echo "PPANEL_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_ENV
- name: Build and push Docker image for ppanel-user-web
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/ppanel-admin-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/ppanel-admin-web:latest
${{ secrets.DOCKER_USERNAME }}/ppanel-admin-web:${{ env.PPANEL_VERSION }}
- name: Build and push Docker image for ppanel-user-web
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/ppanel-user-web/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/ppanel-user-web:latest
${{ secrets.DOCKER_USERNAME }}/ppanel-user-web:${{ env.PPANEL_VERSION }}

View File

@ -1,66 +0,0 @@
name: Build and Publish Docker Image
on:
workflow_dispatch:
release:
types: [published]
push:
branches:
- develop
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
IMAGE_NAME:
- ppanel-user-web
- ppanel-admin-web
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract version from package.json
id: version
run: echo "VERSION=$(jq -r '.version' package.json)" >> $GITHUB_ENV
- name: Get short SHA
id: sha
run: echo "GIT_SHA=${GITHUB_SHA::8}" >> $GITHUB_ENV
- name: Build and push Docker image for main release
if: github.event_name == 'release'
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/${{ matrix.IMAGE_NAME }}/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/${{ matrix.IMAGE_NAME }}:latest
${{ secrets.DOCKER_USERNAME }}/${{ matrix.IMAGE_NAME }}:${{ env.VERSION }}
- name: Build and push Docker image for develop
if: github.ref == 'refs/heads/develop'
uses: docker/build-push-action@v6
with:
context: .
file: ./docker/${{ matrix.IMAGE_NAME }}/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/${{ matrix.IMAGE_NAME }}:beta
${{ secrets.DOCKER_USERNAME }}/${{ matrix.IMAGE_NAME }}:${{ env.VERSION }}-${{ env.GIT_SHA }}-beta

View File

@ -2,8 +2,10 @@ name: Build and Release
on:
push:
branches:
- main
branches: [main, next, beta]
permissions:
contents: write
jobs:
release:
@ -12,34 +14,29 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
node-version: '20'
cache: 'pnpm'
bun-version: 'latest'
- name: Cache pnpm store
- name: Cache Bun dependencies
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
path: |
~/.bun
node_modules
key: ${{ runner.os }}-bun-cache-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
${{ runner.os }}-bun-cache-
- name: Install deps
run: pnpm install
- name: Lint
run: pnpm lint
run: bun install
- name: Build
run: pnpm build
run: bun run build
- name: Release
id: release
run: pnpm release
run: bun run release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}

15
.gitignore vendored
View File

@ -37,3 +37,18 @@ yarn-error.log*
# Misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

10
.npmrc
View File

@ -1,10 +0,0 @@
public-hoist-pattern[]=*typescript*
public-hoist-pattern[]=*tailwindcss*
public-hoist-pattern[]=*autoprefixer*
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=*commitlint*
public-hoist-pattern[]=*semantic-release*
public-hoist-pattern[]=*@umijs/openapi*

View File

@ -1,57 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# Dependencies
node_modules
.pnp
.pnp.js
# Local env files
.env*
# Testing
coverage
# Turbo
.turbo
# Vercel
.vercel
# Build Outputs
.next/
out/
build
dist
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Misc
.DS_Store
*.pem
# Fonts
*.woff
# Images
*.svg
*.ico
# Husky
.husky
# Docker
Dockerfile
# LICENSE
LICENSE
# Ignores
.npmrc
.gitignore
.prettierignore
public
packages/ui/src/lotties/*.json

View File

@ -1 +0,0 @@
module.exports = require('@repo/prettier-config');

View File

@ -10,6 +10,6 @@
"*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts",
"*.jsx": "${capture}.js",
"*.tsx": "${capture}.ts",
"package.json": "*"
"README.md": "*.md, LICENSE"
}
}

View File

@ -58,7 +58,7 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# Install dependencies
pnpm install
bun install
```
## 🤝 Contributing

View File

@ -58,7 +58,7 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# 安装依赖
pnpm install
bun install
```
## 🤝 贡献

40
apps/admin/.gitignore vendored
View File

@ -1,40 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@ -1,39 +0,0 @@
{
"entry": "./locales/en-US",
"entryLocale": "en-US",
"experimental": {
"jsonMode": true
},
"markdown": {
"entry": ["./README.md"],
"entryLocale": "en-US",
"outputLocales": ["zh-CN"]
},
"modelName": "gpt-4o",
"output": "./locales",
"outputLocales": [
"en-US",
"cs-CZ",
"de-DE",
"es-ES",
"es-MX",
"fa-IR",
"fi-FI",
"fr-FR",
"hi-IN",
"hu-HU",
"ja-JP",
"ko-KR",
"no-NO",
"pl-PL",
"pt-BR",
"ro-RO",
"ru-RU",
"th-TH",
"tr-TR",
"uk-UA",
"vi-VN",
"zh-CN",
"zh-HK"
]
}

View File

@ -65,11 +65,11 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# Install dependencies
pnpm install
bun install
# Run the development server
cd apps/admin
pnpm dev
bun dev
```
Open <http://localhost:3000> with your browser to see the result.

View File

@ -65,11 +65,11 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# 安装依赖
pnpm install
bun install
# 运行开发服务器
cd apps/admin
pnpm dev
bun dev
```
在浏览器中打开 <http://localhost:3000> 查看结果。

View File

@ -1,13 +1,13 @@
'use client';
import LanguageSwitch from '@/components/language-switch';
import ThemeSwitch from '@/components/theme-switch';
import useGlobalStore from '@/config/use-global';
import { LoginIcon } from '@repo/ui/lotties';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
import LoginLottie from '@workspace/ui/lotties/login.json';
import { useTranslations } from 'next-intl';
import Image from 'next/legacy/image';
import Link from 'next/link';
import ThemeSwitch from '@/components/theme-switch';
import UserAuthForm from './user-auth-form';
export default function Page() {
@ -30,7 +30,12 @@ export default function Page() {
/>
<span className='text-2xl font-semibold'>{site.site_name}</span>
</Link>
<LoginIcon className='mx-auto hidden w-[275px] md:w-1/2 lg:block xl:w-[500px]' />
<DotLottieReact
className='mx-auto hidden w-full lg:block'
data={LoginLottie}
autoplay
loop
/>
<p className='hidden w-[275px] text-center md:w-1/2 lg:block xl:w-[500px]'>
{site.site_desc}
</p>

View File

@ -1,12 +1,11 @@
'use client';
import useGlobalStore from '@/config/use-global';
import { useLocale } from 'next-intl';
import { useTheme } from 'next-themes';
import { useEffect } from 'react';
import Turnstile, { useTurnstile } from 'react-turnstile';
import useGlobalStore from '@/config/use-global';
export default function CloudFlareTurnstile({
id,
value,

View File

@ -7,10 +7,10 @@ import {
import useGlobalStore from '@/config/use-global';
import { checkUser, resetPassword, userLogin, userRegister } from '@/services/common/auth';
import { getRedirectUrl, setAuthorization } from '@/utils/common';
import { toast } from '@shadcn/ui/lib/sonner';
import { useTranslations } from 'next-intl';
import { useRouter } from 'next/navigation';
import { ReactNode, useState, useTransition } from 'react';
import { toast } from 'sonner';
import UserCheckForm from './user-check-form';
import UserLoginForm from './user-login-form';
import UserRegisterForm from './user-register-form';

View File

@ -1,11 +1,12 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { Button } from '@workspace/ui/components/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { useTranslations } from 'next-intl';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
export default function UserCheckForm({
loading,

View File

@ -1,12 +1,13 @@
import useGlobalStore from '@/config/use-global';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { Button } from '@workspace/ui/components/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { useTranslations } from 'next-intl';
import { Dispatch, SetStateAction } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import CloudFlareTurnstile from './turnstile';
export default function UserLoginForm({

View File

@ -1,15 +1,16 @@
import useGlobalStore from '@/config/use-global';
import { sendEmailCode } from '@/services/common/common';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Markdown } from '@repo/ui/markdown';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { Button } from '@workspace/ui/components/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { Markdown } from '@workspace/ui/custom-components/markdown';
import { useCountDown } from 'ahooks';
import { useTranslations } from 'next-intl';
import { Dispatch, SetStateAction, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import CloudFlareTurnstile from './turnstile';
export default function UserRegisterForm({

View File

@ -1,14 +1,15 @@
import useGlobalStore from '@/config/use-global';
import { sendEmailCode } from '@/services/common/common';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { Button } from '@workspace/ui/components/button';
import { Form, FormControl, FormField, FormItem, FormMessage } from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { useCountDown } from 'ahooks';
import { useTranslations } from 'next-intl';
import { Dispatch, SetStateAction, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import CloudFlareTurnstile from './turnstile';
export default function UserResetForm({

View File

@ -1,11 +1,16 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { MarkdownEditor } from '@repo/ui/editor';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -13,9 +18,12 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
} from '@workspace/ui/components/sheet';
import { MarkdownEditor } from '@workspace/ui/custom-components/editor';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
title: z.string(),

View File

@ -1,20 +1,19 @@
'use client';
import { ProTable, ProTableActions } from '@/components/pro-table';
import {
createAnnouncement,
deleteAnnouncement,
getAnnouncementList,
updateAnnouncement,
} from '@/services/admin/announcement';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { format } from '@shadcn/ui/lib/date-fns';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { format } from 'date-fns';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { ProTable, ProTableActions } from '@/components/pro-table';
import { Button } from '@shadcn/ui/button';
import { toast } from 'sonner';
import NoticeForm from './notice-form';
export default function Page() {

View File

@ -1,17 +1,20 @@
'use client';
import { getSubscribeList } from '@/services/admin/subscribe';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Combobox } from '@repo/ui/combobox';
import { DatePicker } from '@repo/ui/date-picker';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { RadioGroup, RadioGroupItem } from '@shadcn/ui/radio-group';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { RadioGroup, RadioGroupItem } from '@workspace/ui/components/radio-group';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -19,10 +22,15 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/sheet';
import { Combobox } from '@workspace/ui/custom-components/combobox';
import { DatePicker } from '@workspace/ui/custom-components/date-picker';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
name: z.string(),

View File

@ -10,15 +10,15 @@ import {
updateCoupon,
} from '@/services/admin/coupon';
import { getSubscribeList } from '@/services/admin/subscribe';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate } from '@repo/ui/utils';
import { Badge } from '@shadcn/ui/badge';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { useQuery } from '@tanstack/react-query';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import CouponForm from './coupon-form';
export default function Page() {

View File

@ -1,12 +1,16 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { MarkdownEditor } from '@repo/ui/editor';
import { TagInput } from '@repo/ui/tag-input';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { Input } from '@shadcn/ui/input';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { Input } from '@workspace/ui/components/input';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -14,9 +18,13 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
} from '@workspace/ui/components/sheet';
import { MarkdownEditor } from '@workspace/ui/custom-components/editor';
import { TagInput } from '@workspace/ui/custom-components/tag-input';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
title: z.string(),

View File

@ -8,13 +8,13 @@ import {
getDocumentList,
updateDocument,
} from '@/services/admin/document';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import DocumentForm from './document-form';
export default function Page() {

View File

@ -1,6 +1,6 @@
import { Header } from '@/components/header';
import { SidebarLeft } from '@/components/sidebar-left';
import { SidebarInset, SidebarProvider } from '@shadcn/ui/sidebar';
import { SidebarInset, SidebarProvider } from '@workspace/ui/components/sidebar';
import { cookies } from 'next/headers';
export default async function DashboardLayout({ children }: { children: React.ReactNode }) {

View File

@ -8,13 +8,13 @@ import { Display } from '@/components/display';
import { ProTable, ProTableActions } from '@/components/pro-table';
import { getOrderList, updateOrderStatus } from '@/services/admin/order';
import { getSubscribeList } from '@/services/admin/subscribe';
import { Combobox } from '@repo/ui/combobox';
import { formatDate } from '@repo/ui/utils';
import { Badge } from '@shadcn/ui/badge';
import { Button } from '@shadcn/ui/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@shadcn/ui/hover-card';
import { cn } from '@shadcn/ui/lib/utils';
import { Separator } from '@shadcn/ui/separator';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card';
import { Separator } from '@workspace/ui/components/separator';
import { Combobox } from '@workspace/ui/custom-components/combobox';
import { cn } from '@workspace/ui/lib/utils';
import { formatDate } from '@workspace/ui/utils';
import { UserDetail } from '../user/user-detail';
export default function Page() {

View File

@ -1,10 +1,8 @@
'use client';
import { getAlipayF2FPaymentConfig, updateAlipayF2FPaymentConfig } from '@/services/admin/payment';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import {
Select,
SelectContent,
@ -12,12 +10,14 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
} from '@shadcn/ui/select';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { Textarea } from '@shadcn/ui/textarea';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/select';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { Textarea } from '@workspace/ui/components/textarea';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function AlipayF2F() {
const t = useTranslations('payment');

View File

@ -1,10 +1,8 @@
'use client';
import { getEpayPaymentConfig, updateEpayPaymentConfig } from '@/services/admin/payment';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import {
Select,
SelectContent,
@ -12,11 +10,13 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
} from '@shadcn/ui/select';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/select';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Epay() {
const t = useTranslations('payment');

View File

@ -1,5 +1,5 @@
import Billing from '@/components/billing';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import AlipayF2F from './alipayf2f';
import Epay from './epay';
import StripeAlipay from './stripe-alipay';

View File

@ -4,10 +4,8 @@ import {
getStripeAlipayPaymentConfig,
updateStripeAlipayPaymentConfig,
} from '@/services/admin/payment';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import {
Select,
SelectContent,
@ -15,11 +13,13 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
} from '@shadcn/ui/select';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/select';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Stripe() {
const t = useTranslations('payment');

View File

@ -4,10 +4,8 @@ import {
getStripeWeChatPayPaymentConfig,
updateStripeWeChatPayPaymentConfig,
} from '@/services/admin/payment';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import {
Select,
SelectContent,
@ -15,11 +13,13 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
} from '@shadcn/ui/select';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/select';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function StripeWeChatPay() {
const t = useTranslations('payment');

View File

@ -1,4 +1,4 @@
import { z } from '@shadcn/ui/lib/zod';
import { z } from 'zod';
export const protocols = ['shadowsocks', 'vmess', 'vless', 'trojan', 'hysteria2', 'tuic'];

View File

@ -1,12 +1,17 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -14,9 +19,12 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
} from '@workspace/ui/components/sheet';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
name: z.string(),

View File

@ -8,12 +8,12 @@ import {
getNodeGroupList,
updateNodeGroup,
} from '@/services/admin/server';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Button } from '@workspace/ui/components/button';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import GroupForm from './group-form';
export default function GroupTable() {

View File

@ -1,18 +1,27 @@
'use client';
import { getNodeGroupList } from '@/services/admin/server';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Combobox } from '@repo/ui/combobox';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@shadcn/ui/card';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { cn } from '@shadcn/ui/lib/utils';
import { zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shadcn/ui/select';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import {
Sheet,
SheetContent,
@ -20,12 +29,16 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
import { Switch } from '@shadcn/ui/switch';
import { Tabs, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/sheet';
import { Switch } from '@workspace/ui/components/switch';
import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { Combobox } from '@workspace/ui/custom-components/combobox';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { cn } from '@workspace/ui/lib/utils';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { formSchema, protocols } from './form-schema';
interface NodeFormProps<T> {

View File

@ -1,10 +1,15 @@
'use client';
import { formatDate } from '@repo/ui/utils';
import { Badge } from '@shadcn/ui/badge';
import { Progress } from '@shadcn/ui/progress';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@shadcn/ui/tooltip';
import { Badge } from '@workspace/ui/components/badge';
import { Progress } from '@workspace/ui/components/progress';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@workspace/ui/components/tooltip';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
export function formatPercentage(value: number): string {

View File

@ -11,16 +11,21 @@ import {
nodeSort,
updateNode,
} from '@/services/admin/server';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { Badge } from '@shadcn/ui/badge';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { cn } from '@shadcn/ui/lib/utils';
import { Switch } from '@shadcn/ui/switch';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@shadcn/ui/tooltip';
import { useQuery } from '@tanstack/react-query';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from '@workspace/ui/components/tooltip';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { cn } from '@workspace/ui/lib/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import NodeForm from './node-form';
import { NodeStatusCell } from './node-status';

View File

@ -1,4 +1,4 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { getTranslations } from 'next-intl/server';
import GroupTable from './group-table';

View File

@ -1,10 +1,15 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -12,9 +17,12 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
} from '@workspace/ui/components/sheet';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
const formSchema = z.object({
name: z.string(),

View File

@ -8,12 +8,12 @@ import {
getSubscribeGroupList,
updateSubscribeGroup,
} from '@/services/admin/subscribe';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Button } from '@workspace/ui/components/button';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import GroupForm from './group-form';
const GroupTable = () => {

View File

@ -1,6 +1,6 @@
import { getTranslations } from 'next-intl/server';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import GroupTable from './group-table';
import SubscribeTable from './subscribe-table';

View File

@ -1,14 +1,16 @@
import { getNodeGroupList, getNodeList } from '@/services/admin/server';
import { getSubscribeGroupList } from '@/services/admin/subscribe';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { Combobox } from '@repo/ui/combobox';
import { ArrayInput } from '@repo/ui/dynamic-Inputs';
import { JSONEditor } from '@repo/ui/editor';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { evaluateWithPrecision, unitConversion } from '@repo/ui/utils';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@shadcn/ui/accordion';
import { Button } from '@shadcn/ui/button';
import { Checkbox } from '@shadcn/ui/checkbox';
import { useQuery } from '@tanstack/react-query';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@workspace/ui/components/accordion';
import { Button } from '@workspace/ui/components/button';
import { Checkbox } from '@workspace/ui/components/checkbox';
import {
Form,
FormControl,
@ -17,11 +19,9 @@ import {
FormItem,
FormLabel,
FormMessage,
} from '@shadcn/ui/form';
import { Label } from '@shadcn/ui/label';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
} from '@workspace/ui/components/form';
import { Label } from '@workspace/ui/components/label';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -29,11 +29,17 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/sheet';
import { Combobox } from '@workspace/ui/custom-components/combobox';
import { ArrayInput } from '@workspace/ui/custom-components/dynamic-Inputs';
import { JSONEditor } from '@workspace/ui/custom-components/editor';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { evaluateWithPrecision, unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { assign, shake } from 'radash';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
interface SubscribeFormProps<T> {
onSubmit: (data: T) => Promise<boolean> | boolean;

View File

@ -11,14 +11,14 @@ import {
subscribeSort,
updateSubscribe,
} from '@/services/admin/subscribe';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { Badge } from '@shadcn/ui/badge';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { useQuery } from '@tanstack/react-query';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import SubscribeForm from './subscribe-form';
export default function SubscribeTable() {

View File

@ -1,12 +1,12 @@
'use client';
import { getCurrencyConfig, updateCurrencyConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Site() {
const t = useTranslations('system.currency');

View File

@ -1,16 +1,16 @@
'use client';
import { getEmailSmtpConfig, testEmailSmtp, updateEmailSmtpConfig } from '@/services/admin/system';
import { HTMLEditor } from '@repo/ui/editor';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Button } from '@shadcn/ui/button';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { HTMLEditor } from '@workspace/ui/custom-components/editor';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { toast } from 'sonner';
export default function Email() {
const t = useTranslations('system.email');

View File

@ -1,13 +1,13 @@
'use client';
import { getInviteConfig, updateInviteConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Invite() {
const t = useTranslations('system.invite');

View File

@ -2,13 +2,13 @@
import { getNodeConfig, updateNodeConfig } from '@/services/admin/system';
import { Icon } from '@iconify/react';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { nanoid } from 'nanoid';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Node() {
const t = useTranslations('system.node');

View File

@ -1,4 +1,4 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { getTranslations } from 'next-intl/server';
import Currency from './currency';

View File

@ -1,14 +1,14 @@
'use client';
import { getRegisterConfig, updateRegisterConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { Textarea } from '@shadcn/ui/textarea';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { Textarea } from '@workspace/ui/components/textarea';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Register() {
const t = useTranslations('system.register');

View File

@ -1,13 +1,13 @@
'use client';
import { getSiteConfig, updateSiteConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { Textarea } from '@shadcn/ui/textarea';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { Textarea } from '@workspace/ui/components/textarea';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Site() {
const t = useTranslations('system.site');

View File

@ -1,9 +1,9 @@
'use client';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import {
createApplication,
@ -14,14 +14,20 @@ import {
updateApplication,
updateSubscribeConfig,
} from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Button } from '@shadcn/ui/button';
import { Label } from '@shadcn/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shadcn/ui/select';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { Textarea } from '@shadcn/ui/textarea';
import { Button } from '@workspace/ui/components/button';
import { Label } from '@workspace/ui/components/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { Textarea } from '@workspace/ui/components/textarea';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
function compareData(
originalData: API.ApplicationResponse,
@ -124,7 +130,7 @@ export default function Subscription() {
},
});
const [app, setApp] = useState<API.ApplicationResponse>();
const appTypes = Object.keys(apps || {});
const appTypes = Object.keys(apps || {}) as (keyof API.ApplicationResponse)[];
useEffect(() => {
if (!app) setApp(apps);
@ -246,7 +252,7 @@ export default function Subscription() {
})}
</TabsList>
{appTypes.map((type) => {
const list = (app?.[type] as API.Application[]) || [];
const list = (app?.[type] || []) as API.Application[];
const updatedList = (key: string, value: string, index: number) => {
const newList = list.map((item, i) => (i === index ? { ...item, [key]: value } : item));

View File

@ -1,13 +1,13 @@
'use client';
import { getTelegramConfig, updateTelegramConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Telegram() {
const t = useTranslations('system.telegram');

View File

@ -1,10 +1,10 @@
'use client';
import { getTosConfig, updateTosConfig } from '@/services/admin/system';
import { MarkdownEditor } from '@repo/ui/editor';
import { toast } from '@shadcn/ui/lib/sonner';
import { useQuery } from '@tanstack/react-query';
import { MarkdownEditor } from '@workspace/ui/custom-components/editor';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Tos() {
const t = useTranslations('system.tos');

View File

@ -1,13 +1,13 @@
'use client';
import { getVerifyConfig, updateVerifyConfig } from '@/services/admin/system';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Table, TableBody, TableCell, TableRow } from '@shadcn/ui/table';
import { useQuery } from '@tanstack/react-query';
import { Label } from '@workspace/ui/components/label';
import { Switch } from '@workspace/ui/components/switch';
import { Table, TableBody, TableCell, TableRow } from '@workspace/ui/components/table';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
export default function Verify() {
const t = useTranslations('system.verify');

View File

@ -8,9 +8,8 @@ import {
updateTicketStatus,
} from '@/services/admin/ticket';
import { Icon } from '@iconify/react';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import {
Drawer,
DrawerContent,
@ -18,16 +17,17 @@ import {
DrawerFooter,
DrawerHeader,
DrawerTitle,
} from '@shadcn/ui/drawer';
import { Input } from '@shadcn/ui/input';
import { Label } from '@shadcn/ui/label';
import { toast } from '@shadcn/ui/lib/sonner';
import { cn } from '@shadcn/ui/lib/utils';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/drawer';
import { Input } from '@workspace/ui/components/input';
import { Label } from '@workspace/ui/components/label';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { cn } from '@workspace/ui/lib/utils';
import { formatDate } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import NextImage from 'next/legacy/image';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'sonner';
import { UserDetail } from '../user/user-detail';
export default function Page() {

View File

@ -2,7 +2,13 @@
import { getSystemLog, restartSystem } from '@/services/admin/tool';
import { Icon } from '@iconify/react';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@shadcn/ui/accordion';
import { useQuery } from '@tanstack/react-query';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@workspace/ui/components/accordion';
import {
AlertDialog,
AlertDialogAction,
@ -13,12 +19,17 @@ import {
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@shadcn/ui/alert-dialog';
import { Badge } from '@shadcn/ui/badge';
import { Button } from '@shadcn/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@shadcn/ui/card';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/alert-dialog';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
@ -31,7 +42,7 @@ const getLogLevelColor = (level: string) => {
return colorMap[level] || 'bg-gray-100 text-gray-800 hover:bg-gray-200';
};
export default function page() {
export default function Page() {
const t = useTranslations('tool');
const {
data: logs,
@ -131,7 +142,7 @@ export default function page() {
</div>
) : (
<Accordion type='single' collapsible className='w-full'>
{logs?.map((log, index) => (
{logs?.map((log: any, index: number) => (
<AccordionItem key={index} value={`item-${index}`} className='px-4'>
<AccordionTrigger className='hover:no-underline'>
<div className='flex w-full flex-col items-start space-y-2 sm:flex-row sm:items-center sm:space-x-4 sm:space-y-0'>

View File

@ -2,13 +2,13 @@
import { ProTable, ProTableActions } from '@/components/pro-table';
import { createUser, deleteUser, getUserList, updateUser } from '@/services/admin/user';
import { ConfirmButton } from '@repo/ui/confirm-button';
import { formatDate, unitConversion } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { toast } from '@shadcn/ui/lib/sonner';
import { Switch } from '@shadcn/ui/switch';
import { Button } from '@workspace/ui/components/button';
import { Switch } from '@workspace/ui/components/switch';
import { ConfirmButton } from '@workspace/ui/custom-components/confirm-button';
import { formatDate, unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { toast } from 'sonner';
import { UserDetail } from './user-detail';
import UserForm from './user-form';
@ -18,7 +18,7 @@ export default function Page() {
const ref = useRef<ProTableActions>(null);
return (
<ProTable<API.User, any>
<ProTable<API.User, Record<string, unknown>>
action={ref}
header={{
title: t('userList'),

View File

@ -1,10 +1,10 @@
'use client';
import { getUserDetail } from '@/services/admin/user';
import { formatDate, unitConversion } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@shadcn/ui/hover-card';
import { useQuery } from '@tanstack/react-query';
import { Button } from '@workspace/ui/components/button';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@workspace/ui/components/hover-card';
import { formatDate, unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useState } from 'react';

View File

@ -1,13 +1,17 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { Icon } from '@iconify/react';
import { EnhancedInput } from '@repo/ui/enhanced-input';
import { unitConversion } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@shadcn/ui/form';
import { useForm } from '@shadcn/ui/lib/react-hook-form';
import { z, zodResolver } from '@shadcn/ui/lib/zod';
import { ScrollArea } from '@shadcn/ui/scroll-area';
import { Button } from '@workspace/ui/components/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@workspace/ui/components/form';
import { ScrollArea } from '@workspace/ui/components/scroll-area';
import {
Sheet,
SheetContent,
@ -15,10 +19,14 @@ import {
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@shadcn/ui/sheet';
import { Switch } from '@shadcn/ui/switch';
} from '@workspace/ui/components/sheet';
import { Switch } from '@workspace/ui/components/switch';
import { EnhancedInput } from '@workspace/ui/custom-components/enhanced-input';
import { unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
interface UserFormProps<T> {
onSubmit: (data: T) => Promise<boolean> | boolean;
@ -68,7 +76,6 @@ export default function UserForm<T extends Record<string, any>>({
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
size='sm'
onClick={() => {
form.reset();
setOpen(true);

View File

@ -1,18 +1,28 @@
import Providers from '@/components/providers';
import { geistMono, geistSans } from '@/config/fonts';
import { currentUser } from '@/services/admin/user';
import { getGlobalConfig } from '@/services/common/common';
import '@shadcn/ui/globals.css';
import { Toaster } from '@shadcn/ui/sonner';
import { Toaster } from '@workspace/ui/components/sonner';
import '@workspace/ui/globals.css';
import { getLangDir } from '@workspace/ui/hooks/use-lang-dir';
import { Metadata, Viewport } from 'next';
import { NextIntlClientProvider } from 'next-intl';
import { getLocale, getMessages } from 'next-intl/server';
import { PublicEnvScript } from 'next-runtime-env';
import { unstable_noStore as noStore } from 'next/cache';
import { Geist, Geist_Mono } from 'next/font/google';
import { cookies } from 'next/headers';
import NextTopLoader from 'nextjs-toploader';
import React from 'react';
import rtlDetect from 'rtl-detect';
const fontSans = Geist({
subsets: ['latin'],
variable: '--font-sans',
});
const fontMono = Geist_Mono({
subsets: ['latin'],
variable: '--font-mono',
});
export async function generateMetadata(): Promise<Metadata> {
noStore();
@ -24,7 +34,7 @@ export async function generateMetadata(): Promise<Metadata> {
site = config?.site || undefined;
})
.catch((error) => {
console.error('Error fetching global config:', error);
console.log('Error fetching global config:', error);
});
const defaultMetadata = {
@ -60,7 +70,11 @@ export const viewport: Viewport = {
],
};
export default async function RootLayout({ children }: { children: React.ReactNode }) {
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const locale = await getLocale();
const messages = await getMessages();
@ -69,7 +83,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
try {
config = await getGlobalConfig({ skipErrorHandler: true }).then((res) => res.data.data);
} catch (error) {
/* empty */
console.log('Error fetching global config:', error);
}
try {
@ -78,17 +92,17 @@ export default async function RootLayout({ children }: { children: React.ReactNo
Authorization: (await cookies()).get('Authorization')?.value,
}).then((res) => res.data.data);
} catch (error) {
/* empty */
console.log('Error fetching current user:', error);
}
return (
<html suppressHydrationWarning lang={locale} dir={rtlDetect.getLangDir(locale)}>
<html suppressHydrationWarning lang={locale} dir={getLangDir(locale)}>
<head>
<PublicEnvScript />
</head>
<body
suppressHydrationWarning
className={`${geistSans.variable} ${geistMono.variable} size-full min-h-[calc(100dvh-env(safe-area-inset-top))] antialiased`}
className={`${fontSans.variable} ${fontMono.variable} size-full min-h-[calc(100dvh-env(safe-area-inset-top))] font-sans antialiased`}
>
<NextIntlClientProvider messages={messages}>
<NextTopLoader showSpinner={false} />

View File

@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"aliases": {
"components": "@/components",
"hooks": "@/hooks",
"lib": "@/lib",
"utils": "@workspace/ui/lib/utils",
"ui": "@workspace/ui/components"
},
"iconLibrary": "lucide",
"rsc": true,
"style": "new-york",
"tailwind": {
"config": "../../packages/ui/tailwind.config.ts",
"css": "../../packages/ui/src/styles/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"tsx": true
}

View File

@ -1,5 +1,5 @@
import { Avatar, AvatarFallback, AvatarImage } from '@shadcn/ui/avatar';
import { Card, CardDescription, CardHeader, CardTitle } from '@shadcn/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@workspace/ui/components/avatar';
import { Card, CardDescription, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { getTranslations } from 'next-intl/server';
import Link from 'next/link';
@ -25,11 +25,12 @@ export default async function Billing({ type }: BillingProps) {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
const now = new Date().getTime();
list = data[type].filter((item) => {
list = data[type].filter((item: { expiryDate: string }) => {
const expiryDate = Date.parse(item.expiryDate);
return !isNaN(expiryDate) && expiryDate > now;
});
} catch (error) {
console.log('Error fetching billing data:', error);
return null;
}
if (list && list.length === 0) return null;

View File

@ -1,15 +1,25 @@
'use client';
import { queryRevenueStatistics } from '@/services/admin/console';
import { unitConversion } from '@repo/ui/utils';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@shadcn/ui/card';
import { useQuery } from '@tanstack/react-query';
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@shadcn/ui/chart';
} from '@workspace/ui/components/chart';
import { Separator } from '@workspace/ui/components/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { unitConversion } from '@workspace/ui/utils';
import { useLocale, useTranslations } from 'next-intl';
import {
Area,
AreaChart,
@ -20,11 +30,7 @@ import {
Pie,
PieChart,
XAxis,
} from '@shadcn/ui/lib/recharts';
import { Separator } from '@shadcn/ui/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
import { useLocale, useTranslations } from 'next-intl';
} from 'recharts';
import { Display } from '../display';
import { Empty } from '../empty';

View File

@ -2,16 +2,22 @@
import { queryServerTotalData, queryTicketWaitReply } from '@/services/admin/console';
import { Icon } from '@iconify/react';
import { formatBytes } from '@repo/ui/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@shadcn/ui/card';
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@shadcn/ui/chart';
import { Bar, BarChart, CartesianGrid, LabelList, XAxis, YAxis } from '@shadcn/ui/lib/recharts';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shadcn/ui/select';
import { Tabs, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@workspace/ui/components/chart';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { formatBytes } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
import { useState } from 'react';
import { Bar, BarChart, CartesianGrid, LabelList, XAxis, YAxis } from 'recharts';
import { Empty } from '../empty';
import { RevenueStatisticsCard } from './revenue-statistics-card';
import { UserStatisticsCard } from './user-statistics-card';
@ -65,8 +71,8 @@ export default function Statistics() {
})) || [],
},
};
const currentData = trafficData[dataType][timeFrame];
const currentData =
trafficData[dataType as 'nodes' | 'users'][timeFrame as 'today' | 'yesterday'];
return (
<>

View File

@ -1,14 +1,24 @@
'use client';
import { queryUserStatistics } from '@/services/admin/console';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@shadcn/ui/card';
import { useQuery } from '@tanstack/react-query';
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from '@shadcn/ui/chart';
} from '@workspace/ui/components/chart';
import { Separator } from '@workspace/ui/components/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { useLocale, useTranslations } from 'next-intl';
import {
Area,
AreaChart,
@ -19,28 +29,9 @@ import {
Pie,
PieChart,
XAxis,
} from '@shadcn/ui/lib/recharts';
import { Separator } from '@shadcn/ui/separator';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
import { useLocale, useTranslations } from 'next-intl';
} from 'recharts';
import { Empty } from '../empty';
const UserStatisticsConfig = {
register: {
label: '注册',
color: 'hsl(var(--chart-1))',
},
new_purchase: {
label: '新购',
color: 'hsl(var(--chart-2))',
},
repurchase: {
label: '复购',
color: 'hsl(var(--chart-3))',
},
};
export function UserStatisticsCard() {
const t = useTranslations('index');

View File

@ -1,7 +1,7 @@
'use client';
import useGlobalStore from '@/config/use-global';
import { formatBytes, unitConversion } from '@repo/ui/utils';
import { formatBytes, unitConversion } from '@workspace/ui/utils';
import { useTranslations } from 'next-intl';
type DisplayType = 'currency' | 'traffic' | 'number';

View File

@ -1,6 +1,6 @@
'use client';
import { default as _Empty } from '@repo/ui/empty';
import { default as _Empty } from '@workspace/ui/custom-components/empty';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';

View File

@ -7,9 +7,9 @@ import {
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@shadcn/ui/breadcrumb';
import { Separator } from '@shadcn/ui/separator';
import { SidebarTrigger } from '@shadcn/ui/sidebar';
} from '@workspace/ui/components/breadcrumb';
import { Separator } from '@workspace/ui/components/separator';
import { SidebarTrigger } from '@workspace/ui/components/sidebar';
import { useTranslations } from 'next-intl';
import { usePathname } from 'next/navigation';
import { Fragment, useMemo } from 'react';

View File

@ -3,8 +3,14 @@
import { locales } from '@/config/constants';
import { setLocale } from '@/utils/common';
import { Icon } from '@iconify/react';
import { getCountry } from '@repo/ui/utils';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@shadcn/ui/select';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@workspace/ui/components/select';
import { getCountry } from '@workspace/ui/utils';
import { useLocale, useTranslations } from 'next-intl';
import { useRouter } from 'next/navigation';
@ -21,7 +27,7 @@ export default function LanguageSwitch() {
return (
<Select defaultValue={locale} onValueChange={handleLanguageChange}>
<SelectTrigger className='hover:bg-accent hover:text-accent-foreground w-auto border-none bg-transparent p-2 focus:ring-0 [&>svg]:hidden'>
<SelectTrigger className='hover:bg-accent hover:text-accent-foreground w-auto border-none bg-transparent p-2 shadow-none focus:ring-0 [&>svg]:hidden'>
<SelectValue>
<div className='flex items-center'>
<Icon icon={`flagpack:${country?.alpha2.toLowerCase()}`} className='!size-5' />

View File

@ -1,8 +1,8 @@
'use client';
import { ProTable as _ProTable, ProTableProps } from '@repo/ui/pro-table';
import { ProTable as _ProTable, ProTableProps } from '@workspace/ui/custom-components/pro-table';
import { useTranslations } from 'next-intl';
export { type ProTableActions } from '@repo/ui/pro-table';
export { type ProTableActions } from '@workspace/ui/custom-components/pro-table';
export function ProTable<
TData extends Record<string, unknown>,

View File

@ -12,7 +12,7 @@ import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from '@shadcn/ui/sidebar';
} from '@workspace/ui/components/sidebar';
import { useTranslations } from 'next-intl';
import Image from 'next/legacy/image';
import Link from 'next/link';

View File

@ -1,24 +1,25 @@
'use client';
import { MoonIcon, SunIcon } from '@repo/ui/lotties';
import { Button } from '@shadcn/ui/button';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
import { Button } from '@workspace/ui/components/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@shadcn/ui/dropdown-menu';
} from '@workspace/ui/components/dropdown-menu';
import MoonLottie from '@workspace/ui/lotties/moon.json';
import SunLottie from '@workspace/ui/lotties/sun.json';
import { useTheme } from 'next-themes';
export default function ThemeSwitch() {
const { setTheme } = useTheme();
const { setTheme, resolvedTheme } = useTheme();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant='ghost' size='icon'>
<MoonIcon className='size-8 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0' />
<SunIcon className='roate-90 absolute size-8 scale-0 transition-all dark:rotate-0 dark:scale-100' />
<DotLottieReact data={resolvedTheme === 'dark' ? MoonLottie : SunLottie} autoplay loop />
<span className='sr-only'>Toggle theme</span>
</Button>
</DropdownMenuTrigger>

View File

@ -2,8 +2,8 @@
import useGlobalStore from '@/config/use-global';
import { Logout } from '@/utils/common';
import { Avatar, AvatarFallback, AvatarImage } from '@shadcn/ui/avatar';
import { Button } from '@shadcn/ui/button';
import { Avatar, AvatarFallback, AvatarImage } from '@workspace/ui/components/avatar';
import { Button } from '@workspace/ui/components/button';
import {
DropdownMenu,
DropdownMenuContent,
@ -12,7 +12,7 @@ import {
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from '@shadcn/ui/dropdown-menu';
} from '@workspace/ui/components/dropdown-menu';
import { useTranslations } from 'next-intl';
export function UserNav() {

View File

@ -1,9 +1,10 @@
import { env } from 'next-runtime-env';
import i18nConfig from '../.i18nrc.json';
import packageJSON from '../package.json';
export const locales = i18nConfig.outputLocales;
export const locales = packageJSON.i18n.outputLocales;
export const defaultLocale = packageJSON.i18n.entry;
export const NEXT_PUBLIC_DEFAULT_LANGUAGE = env('NEXT_PUBLIC_DEFAULT_LANGUAGE') || locales[0];
export const NEXT_PUBLIC_DEFAULT_LANGUAGE = env('NEXT_PUBLIC_DEFAULT_LANGUAGE') || defaultLocale;
export const NEXT_PUBLIC_SITE_URL = env('NEXT_PUBLIC_SITE_URL');
export const NEXT_PUBLIC_API_URL = env('NEXT_PUBLIC_API_URL');

Binary file not shown.

View File

@ -1,12 +0,0 @@
import localFont from 'next/font/local';
export const geistSans = localFont({
src: './GeistVF.woff',
variable: '--font-geist-sans',
weight: '100 900',
});
export const geistMono = localFont({
src: './GeistMonoVF.woff',
variable: '--font-geist-mono',
weight: '100 900',
});

View File

@ -1,4 +1,4 @@
import { nextJsConfig } from '@repo/eslint-config/next-js';
import { nextJsConfig } from '@workspace/eslint-config/next-js';
/** @type {import("eslint").Linter.Config} */
export default [

View File

@ -4,7 +4,7 @@ import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./locales/request.ts');
const nextConfig: NextConfig = {
transpilePackages: ['@shadcn/ui', '@repo/ui'],
transpilePackages: ['@workspace/ui'],
output: 'standalone',
images: {
remotePatterns: [

View File

@ -11,17 +11,15 @@
},
"dependencies": {
"@iconify/react": "^5.1.0",
"@repo/ui": "workspace:*",
"@shadcn/ui": "workspace:*",
"@tanstack/react-query": "^5.62.7",
"@tanstack/react-query-next-experimental": "^5.62.7",
"@lottiefiles/dotlottie-react": "^0.12.0",
"@tanstack/react-query": "^5.62.10",
"@tanstack/react-query-next-experimental": "^5.62.10",
"@workspace/ui": "workspace:*",
"ahooks": "^3.8.4",
"axios": "^1.7.9",
"crypto-js": "^4.2.0",
"mathjs": "^14.0.1",
"nanoid": "^5.0.9",
"next": "^15.1.0",
"next-intl": "^3.26.1",
"next": "^15.1.2",
"next-intl": "^3.26.3",
"next-runtime-env": "^3.2.2",
"next-themes": "^0.4.4",
"nextjs-toploader": "^3.7.15",
@ -29,17 +27,58 @@
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-turnstile": "^1.1.4",
"rtl-detect": "^1.1.2",
"universal-cookie": "^7.2.2",
"zustand": "^5.0.2"
},
"devDependencies": {
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@types/node": "^22.10.2",
"@types/react": "^19.0.1",
"@types/react": "^19.0.2",
"@types/react-dom": "^19.0.2",
"@types/rtl-detect": "^1.0.3",
"@workspace/eslint-config": "workspace:*",
"@workspace/typescript-config": "workspace:*",
"typescript": "^5.7.2"
},
"i18n": {
"entry": "./locales/en-US",
"entryLocale": "en-US",
"output": "./locales",
"outputLocales": [
"cs-CZ",
"de-DE",
"en-US",
"es-ES",
"es-MX",
"fa-IR",
"fi-FI",
"fr-FR",
"hi-IN",
"hu-HU",
"ja-JP",
"ko-KR",
"no-NO",
"pl-PL",
"pt-BR",
"ro-RO",
"ru-RU",
"th-TH",
"tr-TR",
"uk-UA",
"vi-VN",
"zh-CN",
"zh-HK"
],
"modelName": "gpt-4o",
"experimental": {
"jsonMode": true
},
"markdown": {
"entry": [
"./README.md"
],
"outputLocales": [
"zh-CN"
]
}
}
}

View File

@ -1,9 +1 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
export default config;
export { default } from '@workspace/ui/postcss.config';

View File

@ -1,14 +1 @@
import sharedConfig from '@shadcn/ui/tailwind.config';
import type { Config } from 'tailwindcss';
const config: Config = {
...sharedConfig,
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'../../packages/shadcn/src/components/**/*.{ts,tsx}',
'../../packages/ui/src/**/*.{ts,tsx}',
],
};
export default config;
export * from '@workspace/ui/tailwind.config';

View File

@ -1,17 +1,23 @@
{
"compilerOptions": {
"plugins": [{ "name": "next" }],
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
"@/*": ["./*"],
"@workspace/ui/*": ["../../packages/ui/src/*"]
},
"plugins": [
{
"name": "next"
}
]
},
"exclude": ["node_modules"],
"extends": "@repo/typescript-config/nextjs.json",
"extends": "@workspace/typescript-config/nextjs.json",
"include": [
"next-env.d.ts",
"next.config.mjs",
"**/*.ts",
"**/*.tsx",
"**/*.mjs",
".next/types/**/*.ts",
"services/**/typings.d.ts"
]

View File

@ -1,5 +1,5 @@
import { locales, NEXT_PUBLIC_DEFAULT_LANGUAGE } from '@/config/constants';
import { isBrowser } from '@repo/ui/utils';
import { isBrowser } from '@workspace/ui/utils';
import Cookies from 'universal-cookie';
const cookies = new Cookies(null, {

View File

@ -1,8 +1,8 @@
import { NEXT_PUBLIC_API_URL, NEXT_PUBLIC_SITE_URL } from '@/config/constants';
import { getTranslations } from '@/locales/utils';
import { isBrowser } from '@repo/ui/utils';
import { toast } from '@shadcn/ui/lib/sonner';
import { isBrowser } from '@workspace/ui/utils';
import requset, { InternalAxiosRequestConfig } from 'axios';
import { toast } from 'sonner';
import { getAuthorization, Logout } from './common';
async function handleError(response: any) {

40
apps/user/.gitignore vendored
View File

@ -1,40 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@ -1,39 +0,0 @@
{
"entry": "./locales/en-US",
"entryLocale": "en-US",
"experimental": {
"jsonMode": true
},
"markdown": {
"entry": ["./README.md"],
"entryLocale": "en-US",
"outputLocales": ["zh-CN"]
},
"modelName": "gpt-4o",
"output": "./locales",
"outputLocales": [
"en-US",
"cs-CZ",
"de-DE",
"es-ES",
"es-MX",
"fa-IR",
"fi-FI",
"fr-FR",
"hi-IN",
"hu-HU",
"ja-JP",
"ko-KR",
"no-NO",
"pl-PL",
"pt-BR",
"ro-RO",
"ru-RU",
"th-TH",
"tr-TR",
"uk-UA",
"vi-VN",
"zh-CN",
"zh-HK"
]
}

View File

@ -65,11 +65,11 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# Install dependencies
pnpm install
bun install
# Run the development server
cd apps/user
pnpm dev
bun dev
```
Open <http://localhost:3000> with your browser to see the result.

View File

@ -65,11 +65,11 @@ git clone https://github.com/perfect-panel/ppanel-web.git
cd ppanel-web
# 安装依赖
pnpm install
bun install
# 运行开发服务器
cd apps/user
pnpm dev
bun dev
```
在浏览器中打开 <http://localhost:3000> 查看结果。

View File

@ -4,14 +4,20 @@ import { Empty } from '@/components/empty';
import { ProList } from '@/components/pro-list';
import useGlobalStore from '@/config/use-global';
import { queryUserAffiliate } from '@/services/user/user';
import { formatDate } from '@repo/ui/utils';
import { Button } from '@shadcn/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@shadcn/ui/card';
import { toast } from '@shadcn/ui/lib/sonner';
import { Button } from '@workspace/ui/components/button';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@workspace/ui/components/card';
import { formatDate } from '@workspace/ui/utils';
import { Copy } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import { toast } from 'sonner';
export default function Page() {
const t = useTranslations('affiliate');

View File

@ -2,9 +2,9 @@
import { Empty } from '@/components/empty';
import { queryAnnouncement } from '@/services/user/announcement';
import { Markdown } from '@repo/ui/markdown';
import { Timeline } from '@shadcn/ui/timeline';
import { useQuery } from '@tanstack/react-query';
import { Timeline } from '@workspace/ui/components/timeline';
import { Markdown } from '@workspace/ui/custom-components/markdown';
export default function Page() {
const { data } = useQuery({

View File

@ -4,8 +4,13 @@ import { Display } from '@/components/display';
import { queryApplicationConfig } from '@/services/user/subscribe';
import { queryUserSubscribe } from '@/services/user/user';
import { Icon } from '@iconify/react';
import { getNextResetDate, isBrowser } from '@repo/ui/utils';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@shadcn/ui/accordion';
import { useQuery } from '@tanstack/react-query';
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from '@workspace/ui/components/accordion';
import {
AlertDialog,
AlertDialogAction,
@ -16,19 +21,19 @@ import {
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from '@shadcn/ui/alert-dialog';
import { Button } from '@shadcn/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@shadcn/ui/card';
import { differenceInDays } from '@shadcn/ui/lib/date-fns';
import { toast } from '@shadcn/ui/lib/sonner';
import { Separator } from '@shadcn/ui/separator';
import { Tabs, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
} from '@workspace/ui/components/alert-dialog';
import { Button } from '@workspace/ui/components/button';
import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card';
import { Separator } from '@workspace/ui/components/separator';
import { Tabs, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { getNextResetDate, isBrowser } from '@workspace/ui/utils';
import { differenceInDays } from 'date-fns';
import { useTranslations } from 'next-intl';
import Image from 'next/image';
import Link from 'next/link';
import { QRCodeCanvas } from 'qrcode.react';
import { useState } from 'react';
import { toast } from 'sonner';
import useGlobalStore from '@/config/use-global';
import { getStat } from '@/services/common/common';

View File

@ -1,13 +1,13 @@
'use client';
import { queryDocumentDetail } from '@/services/user/document';
import { Markdown } from '@repo/ui/markdown';
import { formatDate } from '@repo/ui/utils';
import { Avatar, AvatarFallback } from '@shadcn/ui/avatar';
import { buttonVariants } from '@shadcn/ui/button';
import { useOutsideClick } from '@shadcn/ui/hooks/use-outside-click';
import { cn } from '@shadcn/ui/lib/utils';
import { useQuery } from '@tanstack/react-query';
import { Avatar, AvatarFallback } from '@workspace/ui/components/avatar';
import { buttonVariants } from '@workspace/ui/components/button';
import { Markdown } from '@workspace/ui/custom-components/markdown';
import { useOutsideClick } from '@workspace/ui/hooks/use-outside-click';
import { cn } from '@workspace/ui/lib/utils';
import { formatDate } from '@workspace/ui/utils';
import { AnimatePresence, motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { RefObject, useEffect, useId, useRef, useState } from 'react';

View File

@ -2,8 +2,8 @@
import { queryDocumentList } from '@/services/user/document';
import { getTutorialList } from '@/utils/tutorial';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@shadcn/ui/tabs';
import { useQuery } from '@tanstack/react-query';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs';
import { useLocale, useTranslations } from 'next-intl';
import { DocumentButton } from './document-button';
import { TutorialButton } from './tutorial-button';

View File

@ -1,12 +1,12 @@
'use client';
import { getTutorial } from '@/utils/tutorial';
import { Markdown } from '@repo/ui/markdown';
import { Avatar, AvatarFallback } from '@shadcn/ui/avatar';
import { buttonVariants } from '@shadcn/ui/button';
import { useOutsideClick } from '@shadcn/ui/hooks/use-outside-click';
import { cn } from '@shadcn/ui/lib/utils';
import { useQuery } from '@tanstack/react-query';
import { Avatar, AvatarFallback } from '@workspace/ui/components/avatar';
import { buttonVariants } from '@workspace/ui/components/button';
import { Markdown } from '@workspace/ui/custom-components/markdown';
import { useOutsideClick } from '@workspace/ui/hooks/use-outside-click';
import { cn } from '@workspace/ui/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { RefObject, useEffect, useId, useRef, useState } from 'react';

View File

@ -1,5 +1,5 @@
import Announcement from '@/components/announcement';
import { SidebarInset, SidebarProvider } from '@shadcn/ui/sidebar';
import { SidebarInset, SidebarProvider } from '@workspace/ui/components/sidebar';
import { cookies } from 'next/headers';
import { SidebarLeft } from './sidebar-left';
import { SidebarRight } from './sidebar-right';

Some files were not shown because too many files have changed in this diff Show More