♻️ refactor(core): Restructure project for better module separation
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { queryAnnouncement } from '@/services/user/announcement';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { Markdown } from '@repo/ui/markdown';
|
||||
import { Card } from '@shadcn/ui/card';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@shadcn/ui/dialog';
|
||||
import { Card } from '@workspace/ui/components/card';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@workspace/ui/components/dialog';
|
||||
import { Markdown } from '@workspace/ui/custom-components/markdown';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { Empty } from '../empty';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '@/config/constants';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { Icon } from '@iconify/react/dist/iconify.js';
|
||||
import { Separator } from '@shadcn/ui/separator';
|
||||
import { Separator } from '@workspace/ui/components/separator';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { buttonVariants } from '@shadcn/ui/button';
|
||||
import { buttonVariants } from '@workspace/ui/components/button';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Image from 'next/legacy/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
@@ -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' />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { GlobalMapIcon } from '@repo/ui/lotties';
|
||||
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
||||
import GlobalMapLottie from '@workspace/ui/lotties/global-map.json';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
@@ -40,7 +41,7 @@ export function GlobalMap() {
|
||||
delay: 0.4,
|
||||
}}
|
||||
>
|
||||
<GlobalMapIcon className='-mt-[25%] w-full' />
|
||||
<DotLottieReact className='w-full scale-150' data={GlobalMapLottie} autoplay loop />
|
||||
</motion.div>
|
||||
</motion.section>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { NetworkSecurityIcon } from '@repo/ui/lotties';
|
||||
import { HoverBorderGradient } from '@shadcn/ui/hover-border-gradient';
|
||||
import { TextGenerateEffect } from '@shadcn/ui/text-generate-effect';
|
||||
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
||||
import { HoverBorderGradient } from '@workspace/ui/components/hover-border-gradient';
|
||||
import { TextGenerateEffect } from '@workspace/ui/components/text-generate-effect';
|
||||
import NetworkSecurityLottie from '@workspace/ui/lotties/network-security.json';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
@@ -54,7 +55,7 @@ export function Hero() {
|
||||
viewport={{ once: true, amount: 0.3 }}
|
||||
className='flex w-full'
|
||||
>
|
||||
<NetworkSecurityIcon />
|
||||
<DotLottieReact data={NetworkSecurityLottie} autoplay loop />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
@@ -4,14 +4,15 @@ import { SubscribeDetail } from '@/app/(main)/(user)/subscribe/detail';
|
||||
import { Display } from '@/components/display';
|
||||
import { getSubscription } from '@/services/common/common';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { Button } from '@shadcn/ui/button';
|
||||
import { Card, CardContent, CardFooter, CardHeader } from '@shadcn/ui/card';
|
||||
import { cn } from '@shadcn/ui/lib/utils';
|
||||
import { Separator } from '@shadcn/ui/separator';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Button } from '@workspace/ui/components/button';
|
||||
import { Card, CardContent, CardFooter, CardHeader } from '@workspace/ui/components/card';
|
||||
import { Separator } from '@workspace/ui/components/separator';
|
||||
import { cn } from '@workspace/ui/lib/utils';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
import { Key, ReactNode } from 'react';
|
||||
|
||||
export function ProductShowcase() {
|
||||
const t = useTranslations('index');
|
||||
@@ -75,25 +76,35 @@ export function ProductShowcase() {
|
||||
return (
|
||||
<>
|
||||
{description && <li className='text-muted-foreground'>{description}</li>}
|
||||
{features.map((feature, index) => (
|
||||
<li
|
||||
className={cn('flex items-center gap-2', {
|
||||
'text-muted-foreground line-through': feature.type === 'destructive',
|
||||
})}
|
||||
key={index}
|
||||
>
|
||||
{feature.icon && (
|
||||
<Icon
|
||||
icon={feature.icon}
|
||||
className={cn('text-primary size-5', {
|
||||
'text-green-500': feature.type === 'success',
|
||||
'text-destructive': feature.type === 'destructive',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{feature.label}
|
||||
</li>
|
||||
))}
|
||||
{features.map(
|
||||
(
|
||||
feature: {
|
||||
type: string;
|
||||
icon: string;
|
||||
label: ReactNode;
|
||||
},
|
||||
index: Key,
|
||||
) => (
|
||||
<li
|
||||
className={cn('flex items-center gap-2', {
|
||||
'text-muted-foreground line-through':
|
||||
feature.type === 'destructive',
|
||||
})}
|
||||
key={index}
|
||||
>
|
||||
{feature.icon && (
|
||||
<Icon
|
||||
icon={feature.icon}
|
||||
className={cn('text-primary size-5', {
|
||||
'text-green-500': feature.type === 'success',
|
||||
'text-destructive': feature.type === 'destructive',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{feature.label}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { getStat } from '@/services/common/common';
|
||||
import { LocationsIcon, ServersIcon, UsersIcon } from '@repo/ui/lotties';
|
||||
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import LocationsLittie from '@workspace/ui/lotties/locations.json';
|
||||
import ServersLottie from '@workspace/ui/lotties/servers.json';
|
||||
import UsersLottie from '@workspace/ui/lotties/users.json';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -25,17 +28,17 @@ export function Stats() {
|
||||
{
|
||||
name: t('users'),
|
||||
number: data?.user || 999,
|
||||
icon: <UsersIcon className='size-24' />,
|
||||
icon: <DotLottieReact className='size-24' data={UsersLottie} autoplay loop />,
|
||||
},
|
||||
{
|
||||
name: t('servers'),
|
||||
number: data?.server || 30,
|
||||
icon: <ServersIcon className='size-24' />,
|
||||
icon: <DotLottieReact className='size-24' data={ServersLottie} autoplay loop />,
|
||||
},
|
||||
{
|
||||
name: t('locations'),
|
||||
number: data?.country || 10,
|
||||
icon: <LocationsIcon className='size-24' />,
|
||||
icon: <DotLottieReact className='size-24' data={LocationsLittie} autoplay loop />,
|
||||
},
|
||||
];
|
||||
return (
|
||||
@@ -77,12 +80,12 @@ function CountUp({ end, duration = 2000 }: { end: number; duration?: number }) {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
let startTime;
|
||||
let animationFrame;
|
||||
let startTime: number;
|
||||
let animationFrame: number;
|
||||
|
||||
const easeOutQuad = (t) => t * (2 - t);
|
||||
const easeOutQuad = (t: number) => t * (2 - t);
|
||||
|
||||
const updateCount = (timestamp) => {
|
||||
const updateCount = (timestamp: number) => {
|
||||
if (!startTime) startTime = timestamp;
|
||||
const progress = timestamp - startTime;
|
||||
const easedProgress = easeOutQuad(Math.min(progress / duration, 1));
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
import { ProList as _ProList, ProListProps } from '@repo/ui/pro-list';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export { type ProListActions, type ProListProps } from '@repo/ui/pro-list';
|
||||
import { ProList as _ProList, ProListProps } from '@workspace/ui/custom-components/pro-list';
|
||||
import { useTranslations } from 'next-intl';
|
||||
export { type ProListActions, type ProListProps } from '@workspace/ui/custom-components/pro-list';
|
||||
|
||||
export function ProList<TData, TValue extends Record<string, unknown>>(
|
||||
props: ProListProps<TData, TValue>,
|
||||
) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -4,8 +4,8 @@ import { navs } from '@/config/navs';
|
||||
import useGlobalStore from '@/config/use-global';
|
||||
import { Logout } from '@/utils/common';
|
||||
import { Icon } from '@iconify/react';
|
||||
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,
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@shadcn/ui/dropdown-menu';
|
||||
} from '@workspace/ui/components/dropdown-menu';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user