diff --git a/src/lib/ui.ts b/src/lib/ui.ts new file mode 100644 index 0000000..91bbff2 --- /dev/null +++ b/src/lib/ui.ts @@ -0,0 +1,4 @@ +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index edff7a7..e8e0dc9 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -1,6 +1,6 @@ import { UnderConstruction } from '~/components'; -import { isMobile } from '~/lib/utils'; import { VantaNet } from '~/ui'; +import { isMobile } from '~/utils/utils'; export const Home = async () => { const mobile = await isMobile(); diff --git a/src/ui/Button.tsx b/src/ui/Button.tsx index 89517a3..4d241f6 100644 --- a/src/ui/Button.tsx +++ b/src/ui/Button.tsx @@ -1,7 +1,7 @@ import { Slot } from '@radix-ui/react-slot'; import { cva, type VariantProps } from 'class-variance-authority'; import type * as React from 'react'; -import { cn } from '~/lib/utils'; +import { cn } from '~/lib/ui'; export const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", diff --git a/src/ui/Card.tsx b/src/ui/Card.tsx index f234bac..0c9713e 100644 --- a/src/ui/Card.tsx +++ b/src/ui/Card.tsx @@ -1,6 +1,6 @@ import type * as React from 'react'; -import { cn } from '~/lib/utils'; +import { cn } from '~/lib/ui'; export const Card = ({ className, ...props }: React.ComponentProps<'div'>) => { return ( diff --git a/src/utils/utils.spec.ts b/src/utils/utils.spec.ts new file mode 100644 index 0000000..61486e2 --- /dev/null +++ b/src/utils/utils.spec.ts @@ -0,0 +1,42 @@ +const { mockHeaders, mockUserAgentFromString } = vi.hoisted(() => ({ + mockHeaders: vi.fn(), + mockUserAgentFromString: vi.fn(), +})); + +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { isMobile } from './utils'; + +vi.mock('next/headers', () => ({ + headers: mockHeaders, +})); + +vi.mock('next/server', () => ({ + userAgentFromString: mockUserAgentFromString, +})); + +describe('isMobile', () => { + beforeEach(() => { + const headers = new Map(); + headers.set('user-agent', ''); + + mockHeaders.mockReturnValue(headers); + }); + + it('returns true', async () => { + const headers = new Map(); + headers.set('user-agent', ''); + + mockHeaders.mockReturnValue(headers); + mockUserAgentFromString.mockReturnValueOnce({ device: { type: 'mobile' } }); + + const result = await isMobile(); + expect(result).toEqual(true); + }); + + it('returns false with undefined user agent', async () => { + mockUserAgentFromString.mockReturnValueOnce(undefined); + + const result = await isMobile(); + expect(result).toEqual(false); + }); +}); diff --git a/src/lib/utils.ts b/src/utils/utils.ts similarity index 68% rename from src/lib/utils.ts rename to src/utils/utils.ts index 146b7c8..64c21a5 100644 --- a/src/lib/utils.ts +++ b/src/utils/utils.ts @@ -1,9 +1,5 @@ -import { type ClassValue, clsx } from 'clsx'; import { headers } from 'next/headers'; import { userAgentFromString } from 'next/server'; -import { twMerge } from 'tailwind-merge'; - -export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); export const isMobile = async (): Promise => { const headersList = await headers();