Skip to content

Commit 586b58b

Browse files
committed
refactor: definitions
1 parent 7ec925a commit 586b58b

15 files changed

Lines changed: 592 additions & 633 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { LinkProps } from '@tanstack/react-router'
2+
import type { ComponentProps } from 'react'
3+
import { cn } from '@conar/ui/lib/utils'
4+
import { Link } from '@tanstack/react-router'
5+
6+
export function SidebarLink({
7+
className,
8+
...props
9+
}: LinkProps & Omit<ComponentProps<'a'>, 'children'>) {
10+
return (
11+
<Link
12+
activeProps={{ className: 'border-primary/20 bg-primary/10 text-primary hover:bg-primary/20' }}
13+
inactiveProps={{ className: 'border-transparent text-foreground hover:bg-accent/30' }}
14+
className={cn(`
15+
flex w-full items-center gap-2 rounded-md border px-2 py-1 text-sm
16+
`, className)}
17+
{...props}
18+
/>
19+
)
20+
}

apps/desktop/src/routes/_protected/database/$id/definitions.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Sidebar } from './definitions/-components/sidebar'
55
export const Route = createFileRoute(
66
'/_protected/database/$id/definitions',
77
)({
8-
component: DefinitionsSideTabsLayout,
8+
component: DefinitionsLayout,
99
beforeLoad: ({ location, params }) => {
1010
if (location.pathname.endsWith('/definitions') || location.pathname.endsWith('/definitions/')) {
1111
throw redirect({
@@ -17,19 +17,15 @@ export const Route = createFileRoute(
1717
},
1818
})
1919

20-
function DefinitionsSideTabsLayout() {
21-
const { id } = Route.useParams()
22-
const { connection } = Route.useRouteContext()
23-
20+
function DefinitionsLayout() {
2421
return (
2522
<div className="flex size-full gap-1">
26-
<Sidebar connection={connection} id={id} />
23+
<Sidebar />
2724
<ScrollArea className="h-full flex-1 rounded-lg border bg-background">
28-
<ScrollViewport className="
29-
mx-auto flex min-h-full max-w-3xl flex-col px-4 py-6
30-
"
31-
>
32-
<Outlet />
25+
<ScrollViewport>
26+
<div className="mx-auto flex max-w-3xl flex-col px-4 py-6">
27+
<Outlet />
28+
</div>
3329
<ScrollBar />
3430
</ScrollViewport>
3531
</ScrollArea>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { CardContent, MotionCard } from '@conar/ui/components/card'
2+
import { RiInformationLine } from '@remixicon/react'
3+
import { MOTION_BLOCK_PROPS } from '../-constants'
4+
5+
export function DefinitionsEmptyState({ title, description }: {
6+
title: string
7+
description: string
8+
}) {
9+
return (
10+
<MotionCard layout {...MOTION_BLOCK_PROPS}>
11+
<CardContent className="
12+
flex flex-col items-center justify-center p-10 text-center
13+
"
14+
>
15+
<RiInformationLine className="
16+
mx-auto mb-3 size-12 text-muted-foreground
17+
"
18+
/>
19+
<h3 className="text-lg font-medium text-foreground">{title}</h3>
20+
<p className="max-w-md text-sm text-muted-foreground">{description}</p>
21+
</CardContent>
22+
</MotionCard>
23+
)
24+
}

apps/desktop/src/routes/_protected/database/$id/definitions/-components/skeleton.tsx renamed to apps/desktop/src/routes/_protected/database/$id/definitions/-components/grid.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
export function DefinitionsSkeleton() {
1+
import type { ReactNode } from 'react'
2+
import { AnimatePresence } from 'motion/react'
3+
4+
function Skeleton() {
25
return (
36
<div className="space-y-4">
47
{Array.from({ length: 3 }).map((_, i) => (
58
<div
69
key={i}
7-
className="
10+
className={`
811
flex w-full flex-col gap-3 rounded-xl border border-border/40
912
bg-muted/10 p-4
10-
"
13+
`}
1114
>
1215
<div className="flex items-center justify-between">
1316
<div className="flex items-center gap-3">
@@ -28,3 +31,20 @@ export function DefinitionsSkeleton() {
2831
</div>
2932
)
3033
}
34+
35+
export function DefinitionsGrid({ loading, children }: {
36+
loading: boolean
37+
children: ReactNode
38+
}) {
39+
return (
40+
<div className="mt-2 grid grid-cols-1 gap-4">
41+
{loading
42+
? <Skeleton />
43+
: (
44+
<AnimatePresence initial={false} mode="popLayout">
45+
{children}
46+
</AnimatePresence>
47+
)}
48+
</div>
49+
)
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { ReactNode } from 'react'
2+
3+
export function DefinitionsHeader({ title, suffix, children }: {
4+
title: string
5+
suffix?: ReactNode
6+
children: ReactNode
7+
}) {
8+
return (
9+
<div className="mb-4 flex items-center justify-between">
10+
<h2 className="text-2xl font-bold">
11+
{title}
12+
{suffix}
13+
</h2>
14+
<div className="flex items-center gap-2">
15+
{children}
16+
</div>
17+
</div>
18+
)
19+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Input } from '@conar/ui/components/input'
2+
import { cn } from '@conar/ui/lib/utils'
3+
import { RiCloseLine } from '@remixicon/react'
4+
5+
export function DefinitionsSearchInput({
6+
value,
7+
onChange,
8+
placeholder,
9+
className,
10+
}: {
11+
value: string
12+
onChange: (value: string) => void
13+
placeholder: string
14+
className?: string
15+
}) {
16+
return (
17+
<div className="relative">
18+
<Input
19+
placeholder={placeholder}
20+
className={cn('w-[200px] pr-8', className)}
21+
value={value}
22+
autoFocus
23+
onChange={e => onChange(e.target.value)}
24+
/>
25+
{value && (
26+
<button
27+
type="button"
28+
className="
29+
absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer p-1
30+
"
31+
onClick={() => onChange('')}
32+
>
33+
<RiCloseLine className="size-4 text-muted-foreground" />
34+
</button>
35+
)}
36+
</div>
37+
)
38+
}

apps/desktop/src/routes/_protected/database/$id/definitions/-components/sidebar-link.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.

apps/desktop/src/routes/_protected/database/$id/definitions/-components/sidebar.tsx

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@ import type { connections } from '~/drizzle'
33
import type { FileRoutesByTo } from '~/routeTree.gen'
44
import { ConnectionType } from '@conar/shared/enums/connection-type'
55
import { CardTitle } from '@conar/ui/components/card'
6-
import { HighlightText } from '@conar/ui/components/custom/hightlight'
6+
import { HighlightText } from '@conar/ui/components/custom/highlight'
77
import { RiFileList3Line, RiKey2Line, RiListUnordered } from '@remixicon/react'
8-
import { useMatches } from '@tanstack/react-router'
98
import { useStore } from '@tanstack/react-store'
9+
import { SidebarLink } from '~/components/sidebar-link'
1010
import { connectionStore } from '~/entities/connection/store'
11-
import { router } from '~/main'
12-
import { SidebarLink } from './sidebar-link'
13-
14-
interface SidebarProps {
15-
connection: typeof connections.$inferSelect
16-
id: string
17-
}
11+
import { Route } from '../../definitions'
1812

1913
function sidebarItems(connection: typeof connections.$inferSelect) {
2014
return [
@@ -36,28 +30,24 @@ function sidebarItems(connection: typeof connections.$inferSelect) {
3630
] satisfies { Icon: RemixiconComponentType, label: string, to: keyof FileRoutesByTo }[]
3731
}
3832

39-
export function Sidebar({ connection, id }: SidebarProps) {
40-
const search = useStore(connectionStore(id), state => state.definitionsSearch)
41-
const match = useMatches({
42-
select: matches => matches.map(match => router.routesById[match.routeId].to).at(-1),
43-
})
33+
export function Sidebar() {
34+
const { connection } = Route.useRouteContext()
35+
const search = useStore(connectionStore(connection.id), state => state.definitionsSearch)
4436

4537
return (
46-
<aside className="h-full flex-col rounded-lg border bg-background p-4 w-64">
38+
<aside className="h-full w-64 flex-col rounded-lg border bg-background p-4">
4739
<CardTitle className="mb-4">Definitions</CardTitle>
4840
<nav className="space-y-1">
49-
{sidebarItems(connection)
50-
.map(({ to, Icon, label }) => (
51-
<SidebarLink
52-
key={to}
53-
to={to}
54-
params={{ id }}
55-
active={match === to}
56-
>
57-
<Icon className="size-4" />
58-
<HighlightText text={label} match={search} />
59-
</SidebarLink>
60-
))}
41+
{sidebarItems(connection).map(({ to, Icon, label }) => (
42+
<SidebarLink
43+
key={to}
44+
to={to}
45+
params={{ id: connection.id }}
46+
>
47+
<Icon className="size-4" />
48+
<HighlightText text={label} match={search} />
49+
</SidebarLink>
50+
))}
6151
</nav>
6252
</aside>
6353
)

0 commit comments

Comments
 (0)