@lexibase/rdx-ui 0.0.0-stage → 1.0.0-beta.1

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.
package/LICENSE ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright © 2025 Lexibase
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,22 @@
1
- # Temporary Holding Version
1
+ # RDX UI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The shared theme used by the RDX development website and generated documentation
4
+ sites. The source of truth is `packages/rdx-ui/src`: Radix dropdowns, buttons,
5
+ logo, theme provider, navbar, sidebar, landing page and MDX components.
6
+
7
+ Published as `@lexibase/rdx-ui`. React/Next.js source is intentionally shipped
8
+ without bundling so Next.js preserves server/client component boundaries. Add
9
+ the package to `transpilePackages` when using it outside the RDX runtime.
10
+ The RDX runtime already configures this, PostCSS and Tailwind source scanning.
11
+
12
+ ```tsx
13
+ import { Home } from '@lexibase/rdx-ui/components/home'
14
+
15
+ export default function MyHome() {
16
+ return <Home title="My project" />
17
+ }
18
+ ```
19
+
20
+ Configure project-owned components via `homepage.component` and `navbar.logo`.
21
+ Do not edit generated `.rdx/` files. Installing the versioning plugin does not
22
+ change this theme: it contributes data to the shared version dropdown.
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0-beta.1",
4
+ "type": "module",
5
+ "description": "The shared RDX documentation theme and UI components.",
6
+ "license": "MIT",
7
+ "files": [
8
+ "src",
9
+ "postcss.config.mjs",
10
+ "README.md"
11
+ ],
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/lexibase/rdx.git",
18
+ "directory": "packages/rdx-ui"
19
+ },
20
+ "dependencies": {
21
+ "@tailwindcss/postcss": "^4.1.13",
22
+ "postcss": "^8.5.6",
23
+ "tailwindcss": "^4.1.13",
24
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
25
+ "@radix-ui/react-separator": "^1.1.7",
26
+ "@radix-ui/react-slot": "^1.2.3",
27
+ "class-variance-authority": "^0.7.1",
28
+ "clsx": "^2.1.1",
29
+ "lucide-react": "^0.542.0",
30
+ "next-themes": "^0.4.6",
31
+ "tailwind-merge": "^3.3.1",
32
+ "tw-animate-css": "^1.3.8"
33
+ },
34
+ "peerDependencies": {
35
+ "next": "^15.5.0",
36
+ "react": "^19.1.0",
37
+ "react-dom": "^19.1.0"
38
+ },
39
+ "devDependencies": {
40
+ "@tailwindcss/postcss": "^4.1.13",
41
+ "@types/node": "^22.15.3",
42
+ "@types/react": "19.1.0",
43
+ "@types/react-dom": "19.1.1",
44
+ "eslint": "^9.34.0",
45
+ "postcss": "^8.5.6",
46
+ "next": "^15.5.0",
47
+ "react": "19.1.0",
48
+ "react-dom": "19.1.0",
49
+ "tailwindcss": "^4.1.13",
50
+ "typescript": "5.9.2",
51
+ "@rdx/typescript-config": "1.0.0",
52
+ "@rdx/eslint-config": "1.0.0"
53
+ },
54
+ "exports": {
55
+ "./globals.css": "./src/styles/globals.css",
56
+ "./postcss.config": "./postcss.config.mjs",
57
+ "./lib/*": "./src/lib/*.ts",
58
+ "./components/*": "./src/components/*.tsx",
59
+ "./hooks/*": "./src/hooks/*.ts",
60
+ "./contenxts/*": "./src/contexts/*",
61
+ "./providers/*": "./src/providers/*.tsx"
62
+ },
63
+ "scripts": {
64
+ "lint": "eslint . --max-warnings 0",
65
+ "generate:component": "turbo gen react-component",
66
+ "check-types": "tsc --noEmit"
67
+ }
6
68
  }
@@ -0,0 +1,12 @@
1
+ import { createRequire } from 'node:module'
2
+
3
+ const require = createRequire(import.meta.url)
4
+
5
+ /** @type {import('postcss-load-config').Config} */
6
+ const config = {
7
+ plugins: {
8
+ [require.resolve('@tailwindcss/postcss')]: {},
9
+ },
10
+ }
11
+
12
+ export default config
@@ -0,0 +1,70 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Slot } from '@radix-ui/react-slot'
5
+ import { cva, type VariantProps } from 'class-variance-authority'
6
+
7
+ import { cn } from '@lexibase/rdx-ui/lib/utils'
8
+
9
+ const buttonVariants = cva(
10
+ "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",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default:
15
+ 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
16
+ destructive:
17
+ 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 dark:hover:bg-destructive/40',
18
+ outline:
19
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
20
+ primary:
21
+ 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/80',
22
+ secondary:
23
+ 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
24
+ ghost:
25
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
26
+ link: 'text-primary underline-offset-4 hover:underline',
27
+ },
28
+ size: {
29
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
30
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
31
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
32
+ icon: 'size-9',
33
+ link: 'inline-block',
34
+ },
35
+ active: {
36
+ true: 'bg-accent text-accent-foreground dark:bg-accent/50',
37
+ },
38
+ },
39
+ defaultVariants: {
40
+ variant: 'default',
41
+ size: 'default',
42
+ active: false,
43
+ },
44
+ }
45
+ )
46
+
47
+ function Button({
48
+ className,
49
+ variant,
50
+ size,
51
+ active,
52
+ asChild = false,
53
+ ...props
54
+ }: React.ComponentProps<'button'> &
55
+ VariantProps<typeof buttonVariants> & {
56
+ asChild?: boolean
57
+ active?: boolean
58
+ }) {
59
+ const Comp = asChild ? Slot : 'button'
60
+
61
+ return (
62
+ <Comp
63
+ data-slot="button"
64
+ className={cn(buttonVariants({ variant, size, active, className }))}
65
+ {...props}
66
+ />
67
+ )
68
+ }
69
+
70
+ export { Button, buttonVariants }
@@ -0,0 +1,102 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useRef, useState } from 'react'
4
+ import { SidebarClose, SidebarOpen } from 'lucide-react'
5
+ import Link from 'next/link'
6
+
7
+ import { Button } from './button'
8
+ import { Separator } from './separator'
9
+
10
+ export type SidebarCategory = {
11
+ title: string
12
+ links: { href: string; label: string }[]
13
+ }
14
+
15
+ export function DocsSidebar({
16
+ categories,
17
+ pathname,
18
+ }: {
19
+ categories: SidebarCategory[]
20
+ pathname: string
21
+ }) {
22
+ const [isOpen, setIsOpen] = useState(false)
23
+ const dialog = useRef<HTMLDialogElement>(null)
24
+ useEffect(() => {
25
+ if (isOpen && !dialog.current?.open) dialog.current?.showModal()
26
+ if (!isOpen && dialog.current?.open) dialog.current?.close()
27
+ }, [isOpen])
28
+ useEffect(() => {
29
+ setIsOpen(false)
30
+ }, [pathname])
31
+ const content = (
32
+ <nav aria-label="Documentation pages">
33
+ {categories.map((category, index) => (
34
+ <div
35
+ key={`${index}:${category.title}`}
36
+ className="flex flex-col gap-0.5 mb-3 first:mt-4"
37
+ >
38
+ <p className="text-xs text-ring font-semibold uppercase mb-1">
39
+ {category.title}
40
+ </p>
41
+ {category.links.map((link) => (
42
+ <Button
43
+ key={link.href}
44
+ variant="ghost"
45
+ size="sm"
46
+ className="justify-start"
47
+ active={pathname === link.href}
48
+ asChild
49
+ aria-label={link.label}
50
+ >
51
+ <Link
52
+ className="text-sm text-primary"
53
+ href={link.href}
54
+ onClick={() => setIsOpen(false)}
55
+ aria-current={pathname === link.href ? 'page' : undefined}
56
+ >
57
+ {link.label}
58
+ </Link>
59
+ </Button>
60
+ ))}
61
+ {index < categories.length - 1 && <Separator className="my-4" />}
62
+ </div>
63
+ ))}
64
+ </nav>
65
+ )
66
+ return (
67
+ <>
68
+ <div className="md:hidden absolute top-2 left-4 z-30">
69
+ <Button
70
+ variant="ghost"
71
+ onClick={() => setIsOpen(true)}
72
+ aria-label="Open sidebar"
73
+ >
74
+ <SidebarOpen className="size-4" />
75
+ </Button>
76
+ </div>
77
+ <aside
78
+ data-rdx-sidebar
79
+ className="hidden md:block h-full w-40 lg:w-56 shrink-0 border-r border-border overflow-y-auto p-4"
80
+ >
81
+ {content}
82
+ </aside>
83
+ <dialog
84
+ ref={dialog}
85
+ aria-label="Documentation navigation"
86
+ onClose={() => setIsOpen(false)}
87
+ className="fixed inset-0 m-0 h-dvh max-h-none w-full max-w-none bg-background text-foreground border-0 p-4 backdrop:bg-black/40"
88
+ >
89
+ <div className="flex justify-end mb-4">
90
+ <Button
91
+ variant="ghost"
92
+ onClick={() => setIsOpen(false)}
93
+ aria-label="Close sidebar"
94
+ >
95
+ <SidebarClose className="size-4" />
96
+ </Button>
97
+ </div>
98
+ {isOpen && content}
99
+ </dialog>
100
+ </>
101
+ )
102
+ }
@@ -0,0 +1,257 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
5
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'
6
+
7
+ import { cn } from '@lexibase/rdx-ui/lib/utils'
8
+
9
+ function DropdownMenu({
10
+ ...props
11
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
13
+ }
14
+
15
+ function DropdownMenuPortal({
16
+ ...props
17
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18
+ return (
19
+ <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
20
+ )
21
+ }
22
+
23
+ function DropdownMenuTrigger({
24
+ ...props
25
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
26
+ return (
27
+ <DropdownMenuPrimitive.Trigger
28
+ data-slot="dropdown-menu-trigger"
29
+ {...props}
30
+ />
31
+ )
32
+ }
33
+
34
+ function DropdownMenuContent({
35
+ className,
36
+ sideOffset = 4,
37
+ ...props
38
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39
+ return (
40
+ <DropdownMenuPrimitive.Portal>
41
+ <DropdownMenuPrimitive.Content
42
+ data-slot="dropdown-menu-content"
43
+ sideOffset={sideOffset}
44
+ className={cn(
45
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ </DropdownMenuPrimitive.Portal>
51
+ )
52
+ }
53
+
54
+ function DropdownMenuGroup({
55
+ ...props
56
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
57
+ return (
58
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
59
+ )
60
+ }
61
+
62
+ function DropdownMenuItem({
63
+ className,
64
+ inset,
65
+ variant = 'default',
66
+ ...props
67
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
68
+ inset?: boolean
69
+ variant?: 'default' | 'destructive'
70
+ }) {
71
+ return (
72
+ <DropdownMenuPrimitive.Item
73
+ data-slot="dropdown-menu-item"
74
+ data-inset={inset}
75
+ data-variant={variant}
76
+ className={cn(
77
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ function DropdownMenuCheckboxItem({
86
+ className,
87
+ children,
88
+ checked,
89
+ ...props
90
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
91
+ return (
92
+ <DropdownMenuPrimitive.CheckboxItem
93
+ data-slot="dropdown-menu-checkbox-item"
94
+ className={cn(
95
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
96
+ className
97
+ )}
98
+ checked={checked}
99
+ {...props}
100
+ >
101
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
102
+ <DropdownMenuPrimitive.ItemIndicator>
103
+ <CheckIcon className="size-4" />
104
+ </DropdownMenuPrimitive.ItemIndicator>
105
+ </span>
106
+ {children}
107
+ </DropdownMenuPrimitive.CheckboxItem>
108
+ )
109
+ }
110
+
111
+ function DropdownMenuRadioGroup({
112
+ ...props
113
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
114
+ return (
115
+ <DropdownMenuPrimitive.RadioGroup
116
+ data-slot="dropdown-menu-radio-group"
117
+ {...props}
118
+ />
119
+ )
120
+ }
121
+
122
+ function DropdownMenuRadioItem({
123
+ className,
124
+ children,
125
+ ...props
126
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
127
+ return (
128
+ <DropdownMenuPrimitive.RadioItem
129
+ data-slot="dropdown-menu-radio-item"
130
+ className={cn(
131
+ "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132
+ className
133
+ )}
134
+ {...props}
135
+ >
136
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
137
+ <DropdownMenuPrimitive.ItemIndicator>
138
+ <CircleIcon className="size-2 fill-current" />
139
+ </DropdownMenuPrimitive.ItemIndicator>
140
+ </span>
141
+ {children}
142
+ </DropdownMenuPrimitive.RadioItem>
143
+ )
144
+ }
145
+
146
+ function DropdownMenuLabel({
147
+ className,
148
+ inset,
149
+ ...props
150
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
151
+ inset?: boolean
152
+ }) {
153
+ return (
154
+ <DropdownMenuPrimitive.Label
155
+ data-slot="dropdown-menu-label"
156
+ data-inset={inset}
157
+ className={cn(
158
+ 'px-2 py-1.5 text-sm font-medium data-[inset]:pl-8',
159
+ className
160
+ )}
161
+ {...props}
162
+ />
163
+ )
164
+ }
165
+
166
+ function DropdownMenuSeparator({
167
+ className,
168
+ ...props
169
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
170
+ return (
171
+ <DropdownMenuPrimitive.Separator
172
+ data-slot="dropdown-menu-separator"
173
+ className={cn('bg-border -mx-1 my-1 h-px', className)}
174
+ {...props}
175
+ />
176
+ )
177
+ }
178
+
179
+ function DropdownMenuShortcut({
180
+ className,
181
+ ...props
182
+ }: React.ComponentProps<'span'>) {
183
+ return (
184
+ <span
185
+ data-slot="dropdown-menu-shortcut"
186
+ className={cn(
187
+ 'text-muted-foreground ml-auto text-xs tracking-widest',
188
+ className
189
+ )}
190
+ {...props}
191
+ />
192
+ )
193
+ }
194
+
195
+ function DropdownMenuSub({
196
+ ...props
197
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
198
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
199
+ }
200
+
201
+ function DropdownMenuSubTrigger({
202
+ className,
203
+ inset,
204
+ children,
205
+ ...props
206
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
207
+ inset?: boolean
208
+ }) {
209
+ return (
210
+ <DropdownMenuPrimitive.SubTrigger
211
+ data-slot="dropdown-menu-sub-trigger"
212
+ data-inset={inset}
213
+ className={cn(
214
+ 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
215
+ className
216
+ )}
217
+ {...props}
218
+ >
219
+ {children}
220
+ <ChevronRightIcon className="ml-auto size-4" />
221
+ </DropdownMenuPrimitive.SubTrigger>
222
+ )
223
+ }
224
+
225
+ function DropdownMenuSubContent({
226
+ className,
227
+ ...props
228
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
229
+ return (
230
+ <DropdownMenuPrimitive.SubContent
231
+ data-slot="dropdown-menu-sub-content"
232
+ className={cn(
233
+ 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
234
+ className
235
+ )}
236
+ {...props}
237
+ />
238
+ )
239
+ }
240
+
241
+ export {
242
+ DropdownMenu,
243
+ DropdownMenuPortal,
244
+ DropdownMenuTrigger,
245
+ DropdownMenuContent,
246
+ DropdownMenuGroup,
247
+ DropdownMenuLabel,
248
+ DropdownMenuItem,
249
+ DropdownMenuCheckboxItem,
250
+ DropdownMenuRadioGroup,
251
+ DropdownMenuRadioItem,
252
+ DropdownMenuSeparator,
253
+ DropdownMenuShortcut,
254
+ DropdownMenuSub,
255
+ DropdownMenuSubTrigger,
256
+ DropdownMenuSubContent,
257
+ }
@@ -0,0 +1,48 @@
1
+ import type { ReactNode } from 'react'
2
+ import Link from 'next/link'
3
+
4
+ import { Button } from './button'
5
+ import { Logo } from './logo'
6
+
7
+ /** The default landing page from apps/web, not a separate marketing theme. */
8
+ export function Home({
9
+ title = 'RDX',
10
+ logo,
11
+ description,
12
+ buttons = [],
13
+ }: {
14
+ title?: string
15
+ logo?: ReactNode
16
+ description?: string
17
+ buttons?: { label: string; href: string }[]
18
+ }) {
19
+ return (
20
+ <section
21
+ data-rdx-home
22
+ className="w-full h-full flex flex-col items-center justify-center"
23
+ >
24
+ {logo ?? (
25
+ <Logo className="size-52 hover:scale-105 hover:rotate-1 transition-[scale,rotation] duration-1000" />
26
+ )}
27
+ <span className="text-3xl font-mono uppercase">{title}</span>
28
+ {description && (
29
+ <p className="text-sm text-muted-foreground text-center max-w-xl mt-4 px-6">
30
+ {description}
31
+ </p>
32
+ )}
33
+ {buttons.length > 0 && (
34
+ <div className="flex flex-wrap justify-center gap-3 mt-6 px-6">
35
+ {buttons.map((button, index) => (
36
+ <Button
37
+ key={`${index}:${button.href}`}
38
+ variant={index === 0 ? 'default' : 'outline'}
39
+ asChild
40
+ >
41
+ <Link href={button.href}>{button.label}</Link>
42
+ </Button>
43
+ ))}
44
+ </div>
45
+ )}
46
+ </section>
47
+ )
48
+ }
@@ -0,0 +1,19 @@
1
+ import { Spline } from 'lucide-react'
2
+ import { Button } from '@lexibase/rdx-ui/components/button'
3
+
4
+ export function LoadingButton() {
5
+ return (
6
+ <Button
7
+ variant="outline"
8
+ size="sm"
9
+ className="w-[134px] px-9 overflow-hidden"
10
+ disabled
11
+ aria-busy="true"
12
+ aria-label="Loading versions"
13
+ >
14
+ <div className="animate-spin flex items-center justify-center">
15
+ <Spline className="size-4" />
16
+ </div>
17
+ </Button>
18
+ )
19
+ }
@@ -0,0 +1,12 @@
1
+ export const Logo = ({ className }: { className?: string }) => (
2
+ <svg
3
+ xmlns="http://www.w3.org/2000/svg"
4
+ fill="currentColor"
5
+ viewBox="0 0 681 606"
6
+ className={className}
7
+ >
8
+ <path d="m94.3 40.4-2.8 2.4-.3 35.7c-.2 26 0 36.1.9 37.1.7.9 3.2 1.4 7 1.4 4.7 0 6-.4 6.9-1.9.6-1.2 1-12.6 1-30 0-24.8.2-28.1 1.6-28.1 1.4 0 29.9 6.5 67.9 15.5 8.3 1.9 21.8 5.1 30 7 8.3 1.9 21.8 5 30 7 8.3 1.9 24.9 5.8 37 8.6 36.6 8.3 45.5 10.8 55 15.4 14.3 7 24.2 17.2 30.6 31.5l2.4 5.5.3 191.5.2 191.4-4.7-4.6c-10.1-9.7-19.2-15.2-33.5-20.3-5.7-2-7.8-3.2-8.2-4.8-.3-1.2-.6-49.2-.6-106.7l.1-104.5-2.6-2.3c-1.4-1.2-3.5-2.2-4.6-2.2-2.8 0-7.5 2.6-8.3 4.5-.3.9-.6 50.5-.6 110.3-.1 79 .2 109.6 1.1 112 1.3 3.9 1.7 4.1 13.9 8.1 23.7 7.9 39.6 23.5 46 45.1 1.3 4.1 2.7 8.1 3.3 8.7 1.4 1.9 9.1 1.6 11.6-.5 1.2-1 2.7-4.2 3.6-7.7 5-19.7 19.5-35.7 39.4-43.2 3.6-1.4 55.8-14.8 115.9-29.9 60.2-15.1 109.8-27.7 110.4-28 3.9-2.4 3.8 1 3.8-212.9V45.8l-2.9-2.9c-1.8-1.8-4-2.9-5.6-2.9-2.6 0-12.9 2.3-43.5 9.6-8 1.9-23.3 5.5-34 8-10.7 2.4-23.1 5.3-27.5 6.4-13.7 3.3-27.6 6.6-69.5 16.4-22.3 5.3-43.8 10.5-47.8 11.6-15.5 4.3-29.7 13.7-39.5 25.9-3.3 4.2-6.2 7.7-6.6 7.9-.4.1-1.4-1.1-2.4-2.7-6.1-10.3-16.9-20.1-29.9-27-10.2-5.5-19.8-8.3-57.3-16.5-6-1.4-17.7-4.1-26-6.1-8.2-2-25.8-6.1-39-9.1-27.3-6.2-37.3-8.6-96.2-22.4-9.5-2.2-18.6-4-20.2-4-1.7 0-4.2 1-5.8 2.4zm537.5 214.1c-.2 150.9-.6 195.7-1.5 196.3-1.1.7-39 10.2-161.6 40.7-63.3 15.7-69.3 18.1-84.4 32.8l-6.3 6.1v-184c0-202.4-.2-194.9 6-207.8 5.5-11.4 14.6-20.5 26.5-26.4 6.8-3.4 12.5-5 45-12.6 22.7-5.3 82.4-19.4 110.5-26.1 8-1.8 21.5-5 30-7 8.5-1.9 18.9-4.4 23-5.4 4.1-1.1 8.8-2 10.3-2l2.8-.1-.3 195.5z" />
9
+ <path d="M81.1 126.2c-23.8 3.5-44.2 21.1-52.5 45.5-6.9 20.2-5.5 39.8 4.1 59.2 8.1 16.5 25 31.3 42.3 37.2 8.2 2.8 26.2 3.8 35.3 1.9 8-1.6 19.6-7 26.4-12.1l5.3-4v105.5c0 58-.3 105.7-.7 105.9-.5.3-8.4-1.4-17.8-3.7l-17-4.2v-84.6c0-81.8-.1-84.7-1.9-86.7-2.5-2.7-8.5-2.8-11.7-.2l-2.4 1.9-.3 89.6-.2 89.7 2.4 2.4c1.3 1.3 4.8 3 7.7 3.9C113 476.9 149 485 151.8 485c6.6 0 6.2 9.5 6.2-136.2 0-114 .2-131.9 1.5-133.1 1.2-1.3 12.1-1.4 78.2-1.2 80.5.2 81.1.2 82.7-4 1.3-3.6.6-8.2-1.7-10.3l-2.3-2.2H156l-2.9-6.5c-5.3-11.6-17.6-22.3-30-25.9-7.6-2.2-19.4-2.1-27.3.4-16.1 5-26.8 18.8-26.8 34.9 0 12.8 6 23.2 16.5 28.6 5 2.6 7 3 13.4 3 6.3 0 8.6-.5 13.4-2.8 6.9-3.4 9.2-6.4 8.3-10.9-1.3-6.6-5.6-8.4-11.1-4.8-2.1 1.4-4.7 2-8.8 2-5.3 0-6.1-.3-10-3.9-4.2-3.9-4.2-4-4.2-11 0-6.1.4-7.5 3-11.3 4-5.8 11.9-9.8 19.1-9.8 19 0 35.1 18.8 33.1 38.6-1.2 11.5-10.9 25.5-21.3 30.6-14.5 7.3-32.6 7-47.2-.7-12.7-6.6-24.5-20.6-29.2-34.6-6.3-18.6-1.2-42.8 12.1-57.3 5.8-6.3 16.1-12 24.7-13.6 3.3-.6 49.4-1 120.5-1 113.8 0 115.2 0 117.2-2 2.9-2.9 2.7-9.6-.4-12.1-2.1-1.7-4.1-1.9-19.5-1.9-9.4 0-61-.1-114.7-.3-53.7-.1-99.9.1-102.8.5z" />
10
+ <path d="M174.3 244.2c-1.1 1.3-2.3 3.1-2.6 4.1-1 2.7 1.8 8.4 4.4 9.2 1.2.4 33.5.8 71.6.8l69.4.1 2.1-2.2c3.2-3.1 2.8-8.9-.7-11.9l-2.6-2.3H176.3l-2 2.2zM195.9 286.3c-3.9 3-3.9 2.3-3.9 111 0 99 .1 105.6 1.8 107.6.9 1.2 3.4 2.4 5.4 2.7 3 .5 4.1.2 6.2-1.9l2.6-2.6.2-95.3c0-52.4.2-100 .3-105.8.1-10.9-.9-15.2-4-16.4-2.6-1-6.9-.6-8.6.7zM248.4 287.4l-2.8 2.3-.1 119.8v119.7l2.5 2c1.9 1.5 3.4 1.9 6.4 1.5 7.7-1.1 7.1 10.1 7.4-123.3l.2-119.5-2.4-2.4c-3.2-3.2-7.6-3.2-11.2-.1z" />
11
+ </svg>
12
+ )
@@ -0,0 +1,51 @@
1
+ import type { ComponentProps } from 'react'
2
+
3
+ import { Separator } from '@lexibase/rdx-ui/components/separator'
4
+
5
+ export const mdxComponents = {
6
+ h1: (props: ComponentProps<'h1'>) => (
7
+ <h1 className="text-4xl font-bold my-6" {...props} />
8
+ ),
9
+ h2: (props: ComponentProps<'h2'>) => (
10
+ <h2 className="text-2xl font-bold my-6" {...props} />
11
+ ),
12
+ h3: (props: ComponentProps<'h3'>) => (
13
+ <h3 className="text-xl font-bold my-6" {...props} />
14
+ ),
15
+ p: (props: ComponentProps<'p'>) => <p className="my-4" {...props} />,
16
+ ul: (props: ComponentProps<'ul'>) => (
17
+ <ul className="list-disc my-4 ml-6" {...props} />
18
+ ),
19
+ ol: (props: ComponentProps<'ol'>) => (
20
+ <ol className="list-decimal my-4 ml-6" {...props} />
21
+ ),
22
+ li: (props: ComponentProps<'li'>) => (
23
+ <li className="my-2 before:mr-2" {...props} />
24
+ ),
25
+ a: (props: ComponentProps<'a'>) => (
26
+ <a className="underline text-chart-1" {...props} />
27
+ ),
28
+ blockquote: (props: ComponentProps<'blockquote'>) => (
29
+ <blockquote
30
+ className="bg-secondary text-muted-foreground border-l-2 pl-4 py-px my-2"
31
+ {...props}
32
+ />
33
+ ),
34
+ pre: (props: ComponentProps<'pre'>) => (
35
+ <pre
36
+ className="bg-secondary text-secondary-foreground rounded-md p-4 my-4 overflow-x-auto"
37
+ {...props}
38
+ />
39
+ ),
40
+ code: (props: ComponentProps<'code'>) => (
41
+ <code
42
+ className="bg-secondary text-secondary-foreground rounded-sm px-1 py-0.5"
43
+ {...props}
44
+ />
45
+ ),
46
+
47
+ // Custom
48
+ Separator: (props: ComponentProps<typeof Separator>) => (
49
+ <Separator className="my-8" {...props} />
50
+ ),
51
+ }
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+
3
+ import { SunMoon } from 'lucide-react'
4
+ import { useTheme } from 'next-themes'
5
+ import { Button } from '@lexibase/rdx-ui/components/button'
6
+
7
+ export function ModeToggle() {
8
+ const { theme, setTheme } = useTheme()
9
+
10
+ const toggleTheme = () => {
11
+ const nextTheme = theme === 'dark' ? 'light' : 'dark'
12
+ setTheme(nextTheme)
13
+ }
14
+
15
+ return (
16
+ <Button
17
+ size="icon"
18
+ variant="ghost"
19
+ onClick={toggleTheme}
20
+ aria-label="Mode Toggle"
21
+ >
22
+ <SunMoon className="h-[1.2rem] w-[1.2rem]" />
23
+ <span className="sr-only">colorTheme</span>
24
+ </Button>
25
+ )
26
+ }
@@ -0,0 +1,92 @@
1
+ import type { ReactNode } from 'react'
2
+ import { Github } from 'lucide-react'
3
+ import Link from 'next/link'
4
+
5
+ import { Button } from './button'
6
+ import { Logo } from './logo'
7
+ import { Separator } from './separator'
8
+ import { ModeToggle } from './mode-toggle'
9
+
10
+ /** Shared composition extracted from apps/web/components/layout/Navbar. */
11
+ export function Navbar({
12
+ title = '',
13
+ siteTitle = 'RDX',
14
+ logo = <Logo className="size-5" />,
15
+ homeHref = '/',
16
+ docsHref = '/docs',
17
+ docsLink,
18
+ versionMenu,
19
+ github,
20
+ showToggleMode = false,
21
+ }: {
22
+ title?: string
23
+ siteTitle?: string
24
+ logo?: ReactNode
25
+ homeHref?: string
26
+ docsHref?: string
27
+ docsLink?: ReactNode
28
+ versionMenu?: ReactNode
29
+ github?: { visible: boolean; url: string }
30
+ showToggleMode?: boolean
31
+ }) {
32
+ return (
33
+ <nav
34
+ data-rdx-navbar
35
+ aria-label="Main navigation"
36
+ className="w-full flex flex-wrap shrink-0 items-center justify-between px-6 py-2 border-b border-border gap-y-2"
37
+ >
38
+ <div className="flex items-center gap-1">
39
+ <Button
40
+ variant="ghost"
41
+ size={title === '' ? 'icon' : 'default'}
42
+ asChild
43
+ aria-label={siteTitle}
44
+ >
45
+ <Link
46
+ href={homeHref}
47
+ className="cursor-default flex items-center gap-2"
48
+ >
49
+ {logo}
50
+ {title !== '' && <span>{title}</span>}
51
+ </Link>
52
+ </Button>
53
+ </div>
54
+ <div className="flex items-center md:gap-x-2 h-4">
55
+ {versionMenu}
56
+ {docsLink ?? (
57
+ <Button variant="link" size="sm" asChild>
58
+ <Link href={docsHref}>Docs</Link>
59
+ </Button>
60
+ )}
61
+ {github?.visible && github.url && (
62
+ <>
63
+ <Separator orientation="vertical" />
64
+ <Button
65
+ variant="ghost"
66
+ size="icon"
67
+ title="GitHub"
68
+ asChild
69
+ aria-label="GitHub"
70
+ >
71
+ <Link
72
+ className="cursor-default"
73
+ href={github.url}
74
+ target={github.url === '#' ? undefined : '_blank'}
75
+ rel={github.url === '#' ? undefined : 'noopener noreferrer'}
76
+ >
77
+ <Github className="h-[1.2rem] w-[1.2rem]" />
78
+ <span className="sr-only">GitHub</span>
79
+ </Link>
80
+ </Button>
81
+ </>
82
+ )}
83
+ {showToggleMode && (
84
+ <>
85
+ <Separator orientation="vertical" />
86
+ <ModeToggle />
87
+ </>
88
+ )}
89
+ </div>
90
+ </nav>
91
+ )
92
+ }
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as SeparatorPrimitive from '@radix-ui/react-separator'
5
+
6
+ import { cn } from '@lexibase/rdx-ui/lib/utils'
7
+
8
+ function Separator({
9
+ className,
10
+ orientation = 'horizontal',
11
+ decorative = true,
12
+ ...props
13
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
14
+ return (
15
+ <SeparatorPrimitive.Root
16
+ data-slot="separator"
17
+ decorative={decorative}
18
+ orientation={orientation}
19
+ className={cn(
20
+ 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ export { Separator }
@@ -0,0 +1,127 @@
1
+ 'use client'
2
+
3
+ import { Archive, Bird, PackageOpen } from 'lucide-react'
4
+ import Link from 'next/link'
5
+ import type { ReactNode } from 'react'
6
+
7
+ import { Button } from './button'
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuContent,
11
+ DropdownMenuGroup,
12
+ DropdownMenuItem,
13
+ DropdownMenuLabel,
14
+ DropdownMenuSeparator,
15
+ DropdownMenuShortcut,
16
+ DropdownMenuTrigger,
17
+ } from './dropdown-menu'
18
+
19
+ export type VersionOption = {
20
+ id: string
21
+ label: string
22
+ href: string
23
+ kind: 'live' | 'version' | 'archived'
24
+ }
25
+
26
+ function VersionIcon({ kind }: { kind: VersionOption['kind'] }) {
27
+ const Icon =
28
+ kind === 'live' ? Bird : kind === 'archived' ? Archive : PackageOpen
29
+ return <Icon className="size-4" />
30
+ }
31
+
32
+ /** Uses the same Radix primitives, sizes, icons and states as the showcase. */
33
+ export function VersionDropdown({
34
+ options,
35
+ currentId,
36
+ onSelect,
37
+ footer,
38
+ }: {
39
+ options: VersionOption[]
40
+ currentId: string
41
+ onSelect?: (id: string) => void
42
+ footer?: ReactNode
43
+ }) {
44
+ const current =
45
+ options.find((option) => option.id === currentId) ?? options[0]
46
+ if (!current) return null
47
+ const live = options.filter((option) => option.kind === 'live')
48
+ const active = options.filter((option) => option.kind === 'version')
49
+ const archived = options.filter((option) => option.kind === 'archived')
50
+ const item = (option: VersionOption) => {
51
+ const className = `capitalize ${option.id === current.id ? 'bg-accent/30 border-1 border-border' : ''} ${option.kind === 'archived' ? 'text-muted-foreground line-through' : ''}`
52
+ const content = (
53
+ <>
54
+ {option.label}
55
+ <DropdownMenuShortcut>
56
+ <VersionIcon kind={option.kind} />
57
+ </DropdownMenuShortcut>
58
+ </>
59
+ )
60
+ return onSelect ? (
61
+ <DropdownMenuItem
62
+ key={option.id}
63
+ className={className}
64
+ onSelect={() => onSelect(option.id)}
65
+ >
66
+ {content}
67
+ </DropdownMenuItem>
68
+ ) : (
69
+ <DropdownMenuItem key={option.id} className={className} asChild>
70
+ <Link
71
+ href={option.href}
72
+ aria-current={option.id === current.id ? 'true' : undefined}
73
+ >
74
+ {content}
75
+ </Link>
76
+ </DropdownMenuItem>
77
+ )
78
+ }
79
+ return (
80
+ <DropdownMenu>
81
+ <DropdownMenuTrigger asChild>
82
+ <Button
83
+ data-rdx-version-trigger
84
+ variant="outline"
85
+ size="sm"
86
+ className="min-w-[134px] capitalize"
87
+ aria-label={`Documentation version: ${current.label}`}
88
+ >
89
+ {current.label}
90
+ <DropdownMenuShortcut
91
+ className={
92
+ current.kind === 'live'
93
+ ? 'text-blue-500'
94
+ : current.kind === 'archived'
95
+ ? 'text-red-500'
96
+ : 'text-primary'
97
+ }
98
+ >
99
+ <VersionIcon kind={current.kind} />
100
+ </DropdownMenuShortcut>
101
+ </Button>
102
+ </DropdownMenuTrigger>
103
+ <DropdownMenuContent className="w-56" align="start" collisionPadding={8}>
104
+ {live.length > 0 && (
105
+ <>
106
+ <DropdownMenuGroup>{live.map(item)}</DropdownMenuGroup>
107
+ <DropdownMenuSeparator />
108
+ </>
109
+ )}
110
+ {active.map(item)}
111
+ {archived.length > 0 && (
112
+ <>
113
+ <DropdownMenuSeparator />
114
+ <DropdownMenuGroup>
115
+ <DropdownMenuLabel className="text-center py-px cursor-default">
116
+ Archived
117
+ </DropdownMenuLabel>
118
+ <DropdownMenuSeparator />
119
+ {archived.map(item)}
120
+ </DropdownMenuGroup>
121
+ </>
122
+ )}
123
+ {footer}
124
+ </DropdownMenuContent>
125
+ </DropdownMenu>
126
+ )
127
+ }
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from 'clsx'
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,11 @@
1
+ 'use client'
2
+
3
+ import { ThemeProvider as NextThemesProvider } from 'next-themes'
4
+ import * as React from 'react'
5
+
6
+ export function ThemeProvider({
7
+ children,
8
+ ...props
9
+ }: React.ComponentProps<typeof NextThemesProvider>) {
10
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
11
+ }
@@ -0,0 +1,125 @@
1
+ @import 'tailwindcss';
2
+ @source "../**/*.{ts,tsx}";
3
+
4
+ @import 'tw-animate-css';
5
+
6
+ @custom-variant dark (&:is(.dark *));
7
+
8
+ :root {
9
+ --background: oklch(1 0 0);
10
+ --foreground: oklch(0.145 0 0);
11
+ --card: oklch(1 0 0);
12
+ --card-foreground: oklch(0.145 0 0);
13
+ --popover: oklch(1 0 0);
14
+ --popover-foreground: oklch(0.145 0 0);
15
+ --primary: oklch(0.205 0 0);
16
+ --primary-foreground: oklch(0.985 0 0);
17
+ --secondary: oklch(0.97 0 0);
18
+ --secondary-foreground: oklch(0.205 0 0);
19
+ --muted: oklch(0.97 0 0);
20
+ --muted-foreground: oklch(0.556 0 0);
21
+ --accent: oklch(0.97 0 0);
22
+ --accent-foreground: oklch(0.205 0 0);
23
+ --destructive: oklch(0.577 0.245 27.325);
24
+ --destructive-foreground: oklch(0.577 0.245 27.325);
25
+ --border: oklch(0.922 0 0);
26
+ --input: oklch(0.922 0 0);
27
+ --ring: oklch(0.708 0 0);
28
+ --chart-1: oklch(0.646 0.222 41.116);
29
+ --chart-2: oklch(0.6 0.118 184.704);
30
+ --chart-3: oklch(0.398 0.07 227.392);
31
+ --chart-4: oklch(0.828 0.189 84.429);
32
+ --chart-5: oklch(0.769 0.188 70.08);
33
+ --radius: 0.625rem;
34
+ --sidebar: oklch(0.985 0 0);
35
+ --sidebar-foreground: oklch(0.145 0 0);
36
+ --sidebar-primary: oklch(0.205 0 0);
37
+ --sidebar-primary-foreground: oklch(0.985 0 0);
38
+ --sidebar-accent: oklch(0.97 0 0);
39
+ --sidebar-accent-foreground: oklch(0.205 0 0);
40
+ --sidebar-border: oklch(0.922 0 0);
41
+ --sidebar-ring: oklch(0.708 0 0);
42
+ }
43
+
44
+ .dark {
45
+ --background: oklch(0.145 0 0);
46
+ --foreground: oklch(0.985 0 0);
47
+ --card: oklch(0.145 0 0);
48
+ --card-foreground: oklch(0.985 0 0);
49
+ --popover: oklch(0.145 0 0);
50
+ --popover-foreground: oklch(0.985 0 0);
51
+ --primary: oklch(0.985 0 0);
52
+ --primary-foreground: oklch(0.205 0 0);
53
+ --secondary: oklch(0.269 0 0);
54
+ --secondary-foreground: oklch(0.985 0 0);
55
+ --muted: oklch(0.269 0 0);
56
+ --muted-foreground: oklch(0.708 0 0);
57
+ --accent: oklch(0.269 0 0);
58
+ --accent-foreground: oklch(0.985 0 0);
59
+ --destructive: oklch(0.396 0.141 25.723);
60
+ --destructive-foreground: oklch(0.637 0.237 25.331);
61
+ --border: oklch(0.269 0 0);
62
+ --input: oklch(0.269 0 0);
63
+ --ring: oklch(0.556 0 0);
64
+ --chart-1: oklch(0.488 0.243 264.376);
65
+ --chart-2: oklch(0.696 0.17 162.48);
66
+ --chart-3: oklch(0.769 0.188 70.08);
67
+ --chart-4: oklch(0.627 0.265 303.9);
68
+ --chart-5: oklch(0.645 0.246 16.439);
69
+ --sidebar: oklch(0.205 0 0);
70
+ --sidebar-foreground: oklch(0.985 0 0);
71
+ --sidebar-primary: oklch(0.488 0.243 264.376);
72
+ --sidebar-primary-foreground: oklch(0.985 0 0);
73
+ --sidebar-accent: oklch(0.269 0 0);
74
+ --sidebar-accent-foreground: oklch(0.985 0 0);
75
+ --sidebar-border: oklch(0.269 0 0);
76
+ --sidebar-ring: oklch(0.439 0 0);
77
+ }
78
+
79
+ @theme inline {
80
+ --color-background: var(--background);
81
+ --color-foreground: var(--foreground);
82
+ --color-card: var(--card);
83
+ --color-card-foreground: var(--card-foreground);
84
+ --color-popover: var(--popover);
85
+ --color-popover-foreground: var(--popover-foreground);
86
+ --color-primary: var(--primary);
87
+ --color-primary-foreground: var(--primary-foreground);
88
+ --color-secondary: var(--secondary);
89
+ --color-secondary-foreground: var(--secondary-foreground);
90
+ --color-muted: var(--muted);
91
+ --color-muted-foreground: var(--muted-foreground);
92
+ --color-accent: var(--accent);
93
+ --color-accent-foreground: var(--accent-foreground);
94
+ --color-destructive: var(--destructive);
95
+ --color-destructive-foreground: var(--destructive-foreground);
96
+ --color-border: var(--border);
97
+ --color-input: var(--input);
98
+ --color-ring: var(--ring);
99
+ --color-chart-1: var(--chart-1);
100
+ --color-chart-2: var(--chart-2);
101
+ --color-chart-3: var(--chart-3);
102
+ --color-chart-4: var(--chart-4);
103
+ --color-chart-5: var(--chart-5);
104
+ --radius-sm: calc(var(--radius) - 4px);
105
+ --radius-md: calc(var(--radius) - 2px);
106
+ --radius-lg: var(--radius);
107
+ --radius-xl: calc(var(--radius) + 4px);
108
+ --color-sidebar: var(--sidebar);
109
+ --color-sidebar-foreground: var(--sidebar-foreground);
110
+ --color-sidebar-primary: var(--sidebar-primary);
111
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
112
+ --color-sidebar-accent: var(--sidebar-accent);
113
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
114
+ --color-sidebar-border: var(--sidebar-border);
115
+ --color-sidebar-ring: var(--sidebar-ring);
116
+ }
117
+
118
+ @layer base {
119
+ * {
120
+ @apply border-border outline-ring/50;
121
+ }
122
+ body {
123
+ @apply bg-background text-foreground;
124
+ }
125
+ }