@ardly/bunext 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -16
  3. package/cli.mjs +126 -0
  4. package/package.json +14 -58
  5. package/.eslintrc.json +0 -8
  6. package/.prettierignore +0 -4
  7. package/STRUCTURE.md +0 -77
  8. package/bin/cli.mjs +0 -133
  9. package/bin/utils.mjs +0 -32
  10. package/components.json +0 -21
  11. package/next.config.ts +0 -22
  12. package/postcss.config.mjs +0 -8
  13. package/prettier.config.js +0 -7
  14. package/public/android-chrome-192x192.png +0 -0
  15. package/public/android-chrome-512x512.png +0 -0
  16. package/public/favicon.svg +0 -1
  17. package/public/loading-dots.gif +0 -0
  18. package/public/logo.svg +0 -1
  19. package/public/ogImage.webp +0 -0
  20. package/public/site.webmanifest +0 -19
  21. package/src/actions/placeholder.ts +0 -30
  22. package/src/actions/sampleAction.ts +0 -39
  23. package/src/app/(index)/intr/TestCard.tsx +0 -31
  24. package/src/app/(index)/intr/page.tsx +0 -17
  25. package/src/app/(index)/page.tsx +0 -156
  26. package/src/app/(index)/pagetr/page.tsx +0 -37
  27. package/src/app/error-wrapper.tsx +0 -32
  28. package/src/app/global-error.tsx +0 -53
  29. package/src/app/layout.tsx +0 -56
  30. package/src/app/loading.tsx +0 -11
  31. package/src/app/not-found.tsx +0 -45
  32. package/src/app/sitemap.ts +0 -14
  33. package/src/components/Providers/root-provider.tsx +0 -22
  34. package/src/components/Providers/theme-provider.tsx +0 -27
  35. package/src/components/TestComp.tsx +0 -11
  36. package/src/components/brand.tsx +0 -35
  37. package/src/components/navigation/footer.tsx +0 -32
  38. package/src/components/navigation/main-nav.tsx +0 -55
  39. package/src/components/navigation/mobile-nav.tsx +0 -154
  40. package/src/components/navigation/site-header.tsx +0 -67
  41. package/src/components/ui/avatar.tsx +0 -50
  42. package/src/components/ui/badge.tsx +0 -36
  43. package/src/components/ui/button.tsx +0 -56
  44. package/src/components/ui/card.tsx +0 -79
  45. package/src/components/ui/command.tsx +0 -153
  46. package/src/components/ui/dialog.tsx +0 -122
  47. package/src/components/ui/drawer.tsx +0 -118
  48. package/src/components/ui/dropdown-menu.tsx +0 -200
  49. package/src/components/ui/input.tsx +0 -22
  50. package/src/components/ui/label.tsx +0 -26
  51. package/src/components/ui/multi-select.tsx +0 -380
  52. package/src/components/ui/origin/multiselect.tsx +0 -645
  53. package/src/components/ui/popover.tsx +0 -31
  54. package/src/components/ui/radio-group.tsx +0 -44
  55. package/src/components/ui/separator.tsx +0 -31
  56. package/src/components/ui/skeleton.tsx +0 -15
  57. package/src/components/ui/themeSelector.tsx +0 -157
  58. package/src/components/ui/toast.tsx +0 -129
  59. package/src/components/ui/toaster.tsx +0 -31
  60. package/src/components/ui/tooltip.tsx +0 -39
  61. package/src/components/utils/ConditionalLink.tsx +0 -46
  62. package/src/components/utils/Image.tsx +0 -57
  63. package/src/components/utils/Img.tsx +0 -104
  64. package/src/components/utils/Spinner.tsx +0 -29
  65. package/src/components/utils/TopButton.tsx +0 -67
  66. package/src/components/utils/TransitionLink.tsx +0 -67
  67. package/src/components/utils/copy.tsx +0 -98
  68. package/src/components/utils/featureFlag.tsx +0 -22
  69. package/src/components/utils/icons.tsx +0 -155
  70. package/src/components/utils/share-modal.tsx +0 -159
  71. package/src/hooks/use-intersection.ts +0 -52
  72. package/src/hooks/use-lazy-load.ts +0 -33
  73. package/src/hooks/use-meta-color.ts +0 -25
  74. package/src/hooks/use-toast.ts +0 -191
  75. package/src/lib/config/featureflags.ts +0 -63
  76. package/src/lib/config/siteConfig.ts +0 -172
  77. package/src/lib/config/user.ts +0 -9
  78. package/src/lib/data/footer-data.ts +0 -85
  79. package/src/lib/data/nav-data.ts +0 -30
  80. package/src/lib/data/siteData.ts +0 -52
  81. package/src/lib/utils/index.ts +0 -190
  82. package/src/styles/customGlobal.css +0 -141
  83. package/src/styles/globals.css +0 -72
  84. package/src/styles/tailwind/base.ts +0 -46
  85. package/src/styles/tailwind/fonts/ClashDisplay-Bold.eot +0 -0
  86. package/src/styles/tailwind/fonts/ClashDisplay-Bold.ttf +0 -0
  87. package/src/styles/tailwind/fonts/ClashDisplay-Bold.woff +0 -0
  88. package/src/styles/tailwind/fonts/ClashDisplay-Bold.woff2 +0 -0
  89. package/src/styles/tailwind/fonts/ClashDisplay-Extralight.eot +0 -0
  90. package/src/styles/tailwind/fonts/ClashDisplay-Extralight.ttf +0 -0
  91. package/src/styles/tailwind/fonts/ClashDisplay-Extralight.woff +0 -0
  92. package/src/styles/tailwind/fonts/ClashDisplay-Extralight.woff2 +0 -0
  93. package/src/styles/tailwind/fonts/ClashDisplay-Light.eot +0 -0
  94. package/src/styles/tailwind/fonts/ClashDisplay-Light.ttf +0 -0
  95. package/src/styles/tailwind/fonts/ClashDisplay-Light.woff +0 -0
  96. package/src/styles/tailwind/fonts/ClashDisplay-Light.woff2 +0 -0
  97. package/src/styles/tailwind/fonts/ClashDisplay-Medium.eot +0 -0
  98. package/src/styles/tailwind/fonts/ClashDisplay-Medium.ttf +0 -0
  99. package/src/styles/tailwind/fonts/ClashDisplay-Medium.woff +0 -0
  100. package/src/styles/tailwind/fonts/ClashDisplay-Medium.woff2 +0 -0
  101. package/src/styles/tailwind/fonts/ClashDisplay-Regular.eot +0 -0
  102. package/src/styles/tailwind/fonts/ClashDisplay-Regular.ttf +0 -0
  103. package/src/styles/tailwind/fonts/ClashDisplay-Regular.woff +0 -0
  104. package/src/styles/tailwind/fonts/ClashDisplay-Regular.woff2 +0 -0
  105. package/src/styles/tailwind/fonts/ClashDisplay-Semibold.eot +0 -0
  106. package/src/styles/tailwind/fonts/ClashDisplay-Semibold.ttf +0 -0
  107. package/src/styles/tailwind/fonts/ClashDisplay-Semibold.woff +0 -0
  108. package/src/styles/tailwind/fonts/ClashDisplay-Semibold.woff2 +0 -0
  109. package/src/styles/tailwind/fonts/ClashDisplay-Variable.eot +0 -0
  110. package/src/styles/tailwind/fonts/ClashDisplay-Variable.ttf +0 -0
  111. package/src/styles/tailwind/fonts/ClashDisplay-Variable.woff +0 -0
  112. package/src/styles/tailwind/fonts/ClashDisplay-Variable.woff2 +0 -0
  113. package/src/styles/tailwind/fonts/GeistMonoVF.woff +0 -0
  114. package/src/styles/tailwind/fonts/GeistVF.woff +0 -0
  115. package/src/styles/tailwind/fonts.ts +0 -51
  116. package/src/styles/tailwind/tailwindUtils.ts +0 -29
  117. package/src/types/index.ts +0 -80
  118. package/tailwind.config.ts +0 -104
  119. package/tsconfig.json +0 -28
  120. package/vercel.json +0 -6
@@ -1,44 +0,0 @@
1
- 'use client'
2
-
3
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
4
- import { Circle } from 'lucide-react'
5
- import * as React from 'react'
6
-
7
- import { cn } from '@/lib/utils'
8
-
9
- const RadioGroup = React.forwardRef<
10
- React.ElementRef<typeof RadioGroupPrimitive.Root>,
11
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
12
- >(({ className, ...props }, ref) => {
13
- return (
14
- <RadioGroupPrimitive.Root
15
- className={cn('grid gap-2', className)}
16
- {...props}
17
- ref={ref}
18
- />
19
- )
20
- })
21
- RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
22
-
23
- const RadioGroupItem = React.forwardRef<
24
- React.ElementRef<typeof RadioGroupPrimitive.Item>,
25
- React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
26
- >(({ className, ...props }, ref) => {
27
- return (
28
- <RadioGroupPrimitive.Item
29
- ref={ref}
30
- className={cn(
31
- 'aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
32
- className
33
- )}
34
- {...props}
35
- >
36
- <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
37
- <Circle className="h-2.5 w-2.5 fill-current text-current" />
38
- </RadioGroupPrimitive.Indicator>
39
- </RadioGroupPrimitive.Item>
40
- )
41
- })
42
- RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
43
-
44
- export { RadioGroup, RadioGroupItem }
@@ -1,31 +0,0 @@
1
- 'use client'
2
-
3
- import * as React from 'react'
4
- import * as SeparatorPrimitive from '@radix-ui/react-separator'
5
-
6
- import { cn } from '@/lib/utils'
7
-
8
- const Separator = React.forwardRef<
9
- React.ElementRef<typeof SeparatorPrimitive.Root>,
10
- React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
11
- >(
12
- (
13
- { className, orientation = 'horizontal', decorative = true, ...props },
14
- ref
15
- ) => (
16
- <SeparatorPrimitive.Root
17
- ref={ref}
18
- decorative={decorative}
19
- orientation={orientation}
20
- className={cn(
21
- 'shrink-0 bg-border',
22
- orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
23
- className
24
- )}
25
- {...props}
26
- />
27
- )
28
- )
29
- Separator.displayName = SeparatorPrimitive.Root.displayName
30
-
31
- export { Separator }
@@ -1,15 +0,0 @@
1
- import { cn } from '@/lib/utils'
2
-
3
- function Skeleton({
4
- className,
5
- ...props
6
- }: React.HTMLAttributes<HTMLDivElement>) {
7
- return (
8
- <div
9
- className={cn('animate-pulse rounded-md bg-muted', className)}
10
- {...props}
11
- />
12
- )
13
- }
14
-
15
- export { Skeleton }
@@ -1,157 +0,0 @@
1
- 'use client'
2
-
3
- import { LaptopIcon, Moon, Sun } from 'lucide-react'
4
- import { useTheme } from 'next-themes'
5
- import * as React from 'react'
6
-
7
- import { Button } from '@/components/ui/button'
8
- import {
9
- DropdownMenu,
10
- DropdownMenuContent,
11
- DropdownMenuItem,
12
- DropdownMenuTrigger,
13
- } from '@/components/ui/dropdown-menu'
14
- import { Label } from '@/components/ui/label'
15
- import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
16
- import {
17
- Tooltip,
18
- TooltipContent,
19
- TooltipProvider,
20
- TooltipTrigger,
21
- } from '@/components/ui/tooltip'
22
- import { cn } from '@/lib/utils'
23
-
24
- export function ModeDropdown({ className }: { className?: string }) {
25
- const { setTheme, theme } = useTheme()
26
- const [mounted, setMounted] = React.useState(false)
27
-
28
- React.useEffect(() => {
29
- setMounted(true)
30
- }, [])
31
-
32
- if (!mounted) {
33
- return null
34
- }
35
-
36
- return (
37
- <DropdownMenu>
38
- <DropdownMenuTrigger asChild>
39
- <Button
40
- variant="outline"
41
- className={cn('bg-background/5', className)}
42
- size="icon"
43
- >
44
- <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
45
- <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
46
- <span className="sr-only">Toggle theme</span>
47
- </Button>
48
- </DropdownMenuTrigger>
49
- <DropdownMenuContent align="end">
50
- <DropdownMenuItem onClick={() => setTheme('light')}>
51
- Light
52
- </DropdownMenuItem>
53
- <DropdownMenuItem onClick={() => setTheme('dark')}>
54
- Dark
55
- </DropdownMenuItem>
56
- <DropdownMenuItem onClick={() => setTheme('system')}>
57
- System
58
- </DropdownMenuItem>
59
- </DropdownMenuContent>
60
- </DropdownMenu>
61
- )
62
- }
63
-
64
- export function ModeSelector({
65
- className,
66
- iconClassName,
67
- }: {
68
- className?: string
69
- iconClassName?: string
70
- }) {
71
- const { theme, setTheme } = useTheme()
72
- const [mounted, setMounted] = React.useState(false)
73
-
74
- React.useEffect(() => {
75
- setMounted(true)
76
- }, [])
77
-
78
- if (!mounted) {
79
- return null
80
- }
81
-
82
- return (
83
- <TooltipProvider>
84
- <RadioGroup
85
- value={theme}
86
- defaultValue="system"
87
- className={cn(
88
- 'flex gap-0 rounded-3xl border bg-background/65 backdrop-blur-2xl',
89
- className
90
- )}
91
- >
92
- <Tooltip>
93
- <TooltipTrigger asChild>
94
- <Label
95
- htmlFor="light"
96
- className="flex flex-col items-center justify-between rounded-full bg-popover p-2 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:bg-accent"
97
- onClick={() => setTheme('light')}
98
- >
99
- <RadioGroupItem
100
- value="light"
101
- id="light"
102
- className="sr-only"
103
- aria-label="light theme"
104
- />
105
- <Sun className={cn('size-4', iconClassName)} />
106
- </Label>
107
- </TooltipTrigger>
108
- <TooltipContent side="bottom" className="text-xs" showArrow={true}>
109
- <p>Light</p>
110
- </TooltipContent>
111
- </Tooltip>
112
-
113
- <Tooltip>
114
- <TooltipTrigger asChild>
115
- <Label
116
- htmlFor="dark"
117
- className="flex flex-col items-center justify-between rounded-full bg-popover p-2 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:bg-accent"
118
- onClick={() => setTheme('dark')}
119
- >
120
- <RadioGroupItem
121
- value="dark"
122
- id="dark"
123
- className="sr-only"
124
- aria-label="dark theme"
125
- />
126
- <Moon className={cn('size-4', iconClassName)} />
127
- </Label>
128
- </TooltipTrigger>
129
- <TooltipContent side="bottom" className="text-xs" showArrow={true}>
130
- <p>Dark</p>
131
- </TooltipContent>
132
- </Tooltip>
133
-
134
- <Tooltip>
135
- <TooltipTrigger asChild>
136
- <Label
137
- htmlFor="system"
138
- className="flex flex-col items-center justify-between rounded-full bg-popover p-2 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:bg-accent"
139
- onClick={() => setTheme('system')}
140
- >
141
- <RadioGroupItem
142
- value="system"
143
- id="system"
144
- className="sr-only"
145
- aria-label="system theme"
146
- />
147
- <LaptopIcon className={cn('size-4', iconClassName)} />
148
- </Label>
149
- </TooltipTrigger>
150
- <TooltipContent side="bottom" className="text-xs" showArrow={true}>
151
- <p>System</p>
152
- </TooltipContent>
153
- </Tooltip>
154
- </RadioGroup>
155
- </TooltipProvider>
156
- )
157
- }
@@ -1,129 +0,0 @@
1
- 'use client'
2
-
3
- import * as ToastPrimitives from '@radix-ui/react-toast'
4
- import { type VariantProps, cva } from 'class-variance-authority'
5
- import { X } from 'lucide-react'
6
- import * as React from 'react'
7
-
8
- import { cn } from '@/lib/utils'
9
-
10
- const ToastProvider = ToastPrimitives.Provider
11
-
12
- const ToastViewport = React.forwardRef<
13
- React.ElementRef<typeof ToastPrimitives.Viewport>,
14
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
15
- >(({ className, ...props }, ref) => (
16
- <ToastPrimitives.Viewport
17
- ref={ref}
18
- className={cn(
19
- 'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
20
- className
21
- )}
22
- {...props}
23
- />
24
- ))
25
- ToastViewport.displayName = ToastPrimitives.Viewport.displayName
26
-
27
- const toastVariants = cva(
28
- 'group data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[state=closed]:animate-out data-[state=open]:animate-in data-[swipe=end]:animate-out data-[swipe=move]:transition-none',
29
- {
30
- variants: {
31
- variant: {
32
- default: 'border bg-background text-foreground',
33
- destructive:
34
- 'destructive group border-destructive bg-destructive text-destructive-foreground',
35
- },
36
- },
37
- defaultVariants: {
38
- variant: 'default',
39
- },
40
- }
41
- )
42
-
43
- const Toast = React.forwardRef<
44
- React.ElementRef<typeof ToastPrimitives.Root>,
45
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
46
- VariantProps<typeof toastVariants>
47
- >(({ className, variant, ...props }, ref) => {
48
- return (
49
- <ToastPrimitives.Root
50
- ref={ref}
51
- className={cn(toastVariants({ variant }), className)}
52
- {...props}
53
- />
54
- )
55
- })
56
- Toast.displayName = ToastPrimitives.Root.displayName
57
-
58
- const ToastAction = React.forwardRef<
59
- React.ElementRef<typeof ToastPrimitives.Action>,
60
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
61
- >(({ className, ...props }, ref) => (
62
- <ToastPrimitives.Action
63
- ref={ref}
64
- className={cn(
65
- 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive',
66
- className
67
- )}
68
- {...props}
69
- />
70
- ))
71
- ToastAction.displayName = ToastPrimitives.Action.displayName
72
-
73
- const ToastClose = React.forwardRef<
74
- React.ElementRef<typeof ToastPrimitives.Close>,
75
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
76
- >(({ className, ...props }, ref) => (
77
- <ToastPrimitives.Close
78
- ref={ref}
79
- className={cn(
80
- 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
81
- className
82
- )}
83
- toast-close=""
84
- {...props}
85
- >
86
- <X className="h-4 w-4" />
87
- </ToastPrimitives.Close>
88
- ))
89
- ToastClose.displayName = ToastPrimitives.Close.displayName
90
-
91
- const ToastTitle = React.forwardRef<
92
- React.ElementRef<typeof ToastPrimitives.Title>,
93
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
94
- >(({ className, ...props }, ref) => (
95
- <ToastPrimitives.Title
96
- ref={ref}
97
- className={cn('text-sm font-semibold', className)}
98
- {...props}
99
- />
100
- ))
101
- ToastTitle.displayName = ToastPrimitives.Title.displayName
102
-
103
- const ToastDescription = React.forwardRef<
104
- React.ElementRef<typeof ToastPrimitives.Description>,
105
- React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
106
- >(({ className, ...props }, ref) => (
107
- <ToastPrimitives.Description
108
- ref={ref}
109
- className={cn('text-sm opacity-90', className)}
110
- {...props}
111
- />
112
- ))
113
- ToastDescription.displayName = ToastPrimitives.Description.displayName
114
-
115
- type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
116
-
117
- type ToastActionElement = React.ReactElement<typeof ToastAction>
118
-
119
- export {
120
- type ToastProps,
121
- type ToastActionElement,
122
- ToastProvider,
123
- ToastViewport,
124
- Toast,
125
- ToastTitle,
126
- ToastDescription,
127
- ToastClose,
128
- ToastAction,
129
- }
@@ -1,31 +0,0 @@
1
- 'use client'
2
-
3
- import {
4
- Toast,
5
- ToastClose,
6
- ToastDescription,
7
- ToastProvider,
8
- ToastTitle,
9
- ToastViewport,
10
- } from '@/components/ui/toast'
11
- import { useToast } from '@/hooks/use-toast'
12
-
13
- export function Toaster() {
14
- const { toasts } = useToast()
15
-
16
- return (
17
- <ToastProvider>
18
- {toasts.map(({ id, title, description, action, ...props }) => (
19
- <Toast key={id} {...props}>
20
- <div className="grid gap-1">
21
- {title && <ToastTitle>{title}</ToastTitle>}
22
- {description && <ToastDescription>{description}</ToastDescription>}
23
- </div>
24
- {action}
25
- <ToastClose />
26
- </Toast>
27
- ))}
28
- <ToastViewport />
29
- </ToastProvider>
30
- )
31
- }
@@ -1,39 +0,0 @@
1
- 'use client'
2
-
3
- import * as TooltipPrimitive from '@radix-ui/react-tooltip'
4
- import * as React from 'react'
5
-
6
- import { cn } from '@/lib/utils'
7
-
8
- const TooltipProvider = TooltipPrimitive.Provider
9
-
10
- const Tooltip = TooltipPrimitive.Root
11
-
12
- const TooltipTrigger = TooltipPrimitive.Trigger
13
-
14
- const TooltipContent = React.forwardRef<
15
- React.ElementRef<typeof TooltipPrimitive.Content>,
16
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {
17
- showArrow?: boolean
18
- }
19
- >(({ className, sideOffset = 4, showArrow = false, ...props }, ref) => (
20
- <TooltipPrimitive.Portal>
21
- <TooltipPrimitive.Content
22
- ref={ref}
23
- sideOffset={sideOffset}
24
- className={cn(
25
- 'relative z-50 max-w-[280px] rounded-lg border border-border bg-popover px-3 py-1.5 text-sm text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
26
- className
27
- )}
28
- {...props}
29
- >
30
- {props.children}
31
- {showArrow && (
32
- <TooltipPrimitive.Arrow className="-my-px fill-popover drop-shadow-[0_1px_0_hsl(var(--border))]" />
33
- )}
34
- </TooltipPrimitive.Content>
35
- </TooltipPrimitive.Portal>
36
- ))
37
- TooltipContent.displayName = TooltipPrimitive.Content.displayName
38
-
39
- export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
@@ -1,46 +0,0 @@
1
- // components/UnstyledLink.tsx
2
- import { cn } from '@/lib/utils'
3
- import Link, { LinkProps } from 'next/link'
4
-
5
- export type UnstyledLinkProps = {
6
- href: string
7
- children: React.ReactNode
8
- openNewTab?: boolean
9
- className?: string
10
- } & React.ComponentPropsWithoutRef<'a'> &
11
- LinkProps
12
-
13
- export default function CLink({
14
- children,
15
- href,
16
- openNewTab,
17
- className,
18
- ...rest
19
- }: UnstyledLinkProps) {
20
- const isNewTab =
21
- openNewTab !== undefined
22
- ? openNewTab
23
- : href && !href.startsWith('/') && !href.startsWith('#')
24
-
25
- if (!isNewTab) {
26
- return (
27
- <Link href={href}>
28
- <a {...rest} className={className}>
29
- {children}
30
- </a>
31
- </Link>
32
- )
33
- }
34
-
35
- return (
36
- <a
37
- target="_blank"
38
- rel="noopener noreferrer"
39
- href={href}
40
- {...rest}
41
- className={cn(className, 'cursor-newtab')}
42
- >
43
- {children}
44
- </a>
45
- )
46
- }
@@ -1,57 +0,0 @@
1
- import NextImageComponent from 'next/image'
2
- import type React from 'react'
3
- import type { ImgProps } from '@/types'
4
- import { cleanSrc, shimmer, svgToBase64 } from '@/lib/utils'
5
- // auto generate placeholder image
6
-
7
- function Img({ src, width, height, alt, ...props }: ImgProps) {
8
- return (
9
- <NextImageComponent
10
- width={width || 500}
11
- height={height || width || 300}
12
- alt={
13
- alt ||
14
- src.substring(src.lastIndexOf('/') + 1).slice(0, 20) ||
15
- 'Picture Element'
16
- }
17
- src={cleanSrc(src as string)}
18
- draggable="false"
19
- sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
20
- {...(props as any)}
21
- />
22
- )
23
- }
24
-
25
- export const Image: React.FC<ImgProps> = ({ placeholder, ...props }) => {
26
- const imgComp: Record<string, React.ReactNode> = {
27
- blur: <BlurImg {...props} />,
28
- shimmer: (
29
- <Img
30
- {...props}
31
- placeholder={`data:image/svg+xml;base64,${svgToBase64(
32
- shimmer(500, 300)
33
- )}`}
34
- alt={props.alt || ''}
35
- />
36
- ),
37
- }
38
- return (
39
- (placeholder && imgComp[placeholder]) || (
40
- <Img placeholder={placeholder} {...props} alt={props.alt || ''} />
41
- )
42
- )
43
- }
44
-
45
- const BlurImg = async (props: ImgProps) => {
46
- const blurData = await import('@/actions/placeholder').then((f) =>
47
- f.getPlaceholderImage(props.src)
48
- )
49
- return (
50
- <Img
51
- placeholder="blur"
52
- blurDataURL={blurData}
53
- alt={props.alt || ''}
54
- {...props}
55
- />
56
- )
57
- }
@@ -1,104 +0,0 @@
1
- 'use client'
2
- import { useState } from 'react'
3
- import { Skeleton } from '@/components/ui/skeleton'
4
- import { useLazyLoad } from '@/hooks/use-lazy-load'
5
- import { cn } from '@/lib/utils'
6
- // lazy loads imgs with a placeholder on the client side
7
- // does not optimizes images, just lazy loads them client side with a skeleton placeholder
8
- interface ResponsiveImageProps
9
- extends React.ImgHTMLAttributes<HTMLImageElement> {
10
- src: string
11
- alt: string
12
- width: number
13
- height: number
14
- className?: string
15
- skeletonClassName?: string
16
- }
17
-
18
- export function Img({
19
- src,
20
- alt,
21
- width,
22
- height,
23
- className = '',
24
- skeletonClassName = '',
25
- ...restProps
26
- }: ResponsiveImageProps) {
27
- const [imageRef, isInView] = useLazyLoad()
28
- const [isLoaded, setIsLoaded] = useState(false)
29
- const [hasError, setHasError] = useState(false)
30
- const aspectRatio = `${width} / ${height}`
31
- const showAltText = width > 100 && height > 100
32
-
33
- return (
34
- <div
35
- ref={imageRef}
36
- className={cn('relative w-full overflow-hidden', className)}
37
- style={{
38
- aspectRatio: aspectRatio,
39
- maxWidth: `${width}px`,
40
- }}
41
- >
42
- {/* fallback for users with JS disabled */}
43
- <noscript>
44
- <img
45
- {...restProps}
46
- src={src}
47
- alt={alt}
48
- width={width}
49
- height={height}
50
- className="absolute left-0 top-0 h-full w-full object-cover"
51
- />
52
- </noscript>
53
-
54
- {isInView ? (
55
- <img
56
- {...restProps}
57
- src={src}
58
- alt={alt}
59
- width={width}
60
- height={height}
61
- className={cn(
62
- 'absolute left-0 top-0 h-full w-full object-cover transition-opacity duration-300',
63
- isLoaded && !hasError ? 'opacity-100' : 'opacity-0'
64
- )}
65
- onLoad={() => setIsLoaded(true)}
66
- onError={() => setHasError(true)}
67
- loading="lazy"
68
- />
69
- ) : null}
70
- {!isLoaded && (
71
- <Skeleton
72
- className={cn(
73
- 'absolute left-0 top-0 h-full w-full rounded-none',
74
- skeletonClassName,
75
- hasError && '[animation-play-state:paused]'
76
- )}
77
- />
78
- )}
79
- {hasError && (
80
- <div className="absolute inset-0 flex flex-col items-center justify-center text-red-600">
81
- <svg
82
- xmlns="http://www.w3.org/2000/svg"
83
- width="24"
84
- height="24"
85
- viewBox="0 0 24 24"
86
- fill="none"
87
- stroke="currentColor"
88
- stroke-width="2"
89
- stroke-linecap="round"
90
- stroke-linejoin="round"
91
- className="h-[30%] max-h-[40px] min-h-[30px] w-[30%] min-w-[30px] max-w-[40px]"
92
- >
93
- <circle cx="12" cy="12" r="10"></circle>
94
- <line x1="12" y1="8" x2="12" y2="12"></line>
95
- <line x1="12" y1="16" x2="12.01" y2="16"></line>
96
- </svg>
97
- {showAltText && (
98
- <span className="mt-2 px-2 text-center text-sm">{alt}</span>
99
- )}
100
- </div>
101
- )}
102
- </div>
103
- )
104
- }
@@ -1,29 +0,0 @@
1
- import { Icons } from '@/components/utils/icons'
2
- import { cn } from '@/lib/utils'
3
- // a simple spinner fallback for suspanse components
4
- export const SuspanseFallback = ({
5
- className,
6
- spinnerClassName,
7
- }: {
8
- className?: string
9
- spinnerClassName?: string
10
- }) => {
11
- if (!Icons?.spinner)
12
- return (
13
- <div className={cn('grid h-full w-full place-items-center', className)}>
14
- <div
15
- className={cn(
16
- 'size-10 animate-spin rounded-full border-2 border-primary border-t-transparent',
17
- spinnerClassName
18
- )}
19
- />
20
- </div>
21
- )
22
- return (
23
- <div className={cn('grid h-full w-full place-items-center', className)}>
24
- <Icons.spinner
25
- className={cn('size-10 animate-spin text-primary', spinnerClassName)}
26
- />
27
- </div>
28
- )
29
- }