@gmickel/gno 0.3.5 → 0.5.0
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/README.md +74 -7
- package/package.json +30 -1
- package/src/cli/commands/ask.ts +12 -187
- package/src/cli/commands/embed.ts +10 -4
- package/src/cli/commands/models/pull.ts +9 -4
- package/src/cli/commands/serve.ts +19 -0
- package/src/cli/commands/vsearch.ts +5 -2
- package/src/cli/program.ts +28 -0
- package/src/config/types.ts +11 -6
- package/src/llm/registry.ts +3 -1
- package/src/mcp/tools/vsearch.ts +5 -2
- package/src/pipeline/answer.ts +224 -0
- package/src/pipeline/contextual.ts +57 -0
- package/src/pipeline/expansion.ts +49 -31
- package/src/pipeline/explain.ts +11 -3
- package/src/pipeline/fusion.ts +20 -9
- package/src/pipeline/hybrid.ts +57 -40
- package/src/pipeline/index.ts +7 -0
- package/src/pipeline/rerank.ts +55 -27
- package/src/pipeline/types.ts +0 -3
- package/src/pipeline/vsearch.ts +3 -2
- package/src/serve/CLAUDE.md +91 -0
- package/src/serve/bunfig.toml +2 -0
- package/src/serve/context.ts +181 -0
- package/src/serve/index.ts +7 -0
- package/src/serve/public/app.tsx +56 -0
- package/src/serve/public/components/ai-elements/code-block.tsx +176 -0
- package/src/serve/public/components/ai-elements/conversation.tsx +98 -0
- package/src/serve/public/components/ai-elements/inline-citation.tsx +285 -0
- package/src/serve/public/components/ai-elements/loader.tsx +96 -0
- package/src/serve/public/components/ai-elements/message.tsx +443 -0
- package/src/serve/public/components/ai-elements/prompt-input.tsx +1421 -0
- package/src/serve/public/components/ai-elements/sources.tsx +75 -0
- package/src/serve/public/components/ai-elements/suggestion.tsx +51 -0
- package/src/serve/public/components/preset-selector.tsx +403 -0
- package/src/serve/public/components/ui/badge.tsx +46 -0
- package/src/serve/public/components/ui/button-group.tsx +82 -0
- package/src/serve/public/components/ui/button.tsx +62 -0
- package/src/serve/public/components/ui/card.tsx +92 -0
- package/src/serve/public/components/ui/carousel.tsx +244 -0
- package/src/serve/public/components/ui/collapsible.tsx +31 -0
- package/src/serve/public/components/ui/command.tsx +181 -0
- package/src/serve/public/components/ui/dialog.tsx +141 -0
- package/src/serve/public/components/ui/dropdown-menu.tsx +255 -0
- package/src/serve/public/components/ui/hover-card.tsx +42 -0
- package/src/serve/public/components/ui/input-group.tsx +167 -0
- package/src/serve/public/components/ui/input.tsx +21 -0
- package/src/serve/public/components/ui/progress.tsx +28 -0
- package/src/serve/public/components/ui/scroll-area.tsx +56 -0
- package/src/serve/public/components/ui/select.tsx +188 -0
- package/src/serve/public/components/ui/separator.tsx +26 -0
- package/src/serve/public/components/ui/table.tsx +114 -0
- package/src/serve/public/components/ui/textarea.tsx +18 -0
- package/src/serve/public/components/ui/tooltip.tsx +59 -0
- package/src/serve/public/globals.css +226 -0
- package/src/serve/public/hooks/use-api.ts +112 -0
- package/src/serve/public/index.html +13 -0
- package/src/serve/public/pages/Ask.tsx +442 -0
- package/src/serve/public/pages/Browse.tsx +270 -0
- package/src/serve/public/pages/Dashboard.tsx +202 -0
- package/src/serve/public/pages/DocView.tsx +302 -0
- package/src/serve/public/pages/Search.tsx +335 -0
- package/src/serve/routes/api.ts +763 -0
- package/src/serve/server.ts +249 -0
- package/src/store/migrations/002-documents-fts.ts +40 -0
- package/src/store/migrations/index.ts +2 -1
- package/src/store/sqlite/adapter.ts +216 -33
- package/src/store/sqlite/fts5-snowball.ts +144 -0
- package/src/store/types.ts +33 -3
- package/src/store/vector/stats.ts +3 -0
- package/src/store/vector/types.ts +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
function ScrollArea({
|
|
7
|
+
className,
|
|
8
|
+
children,
|
|
9
|
+
...props
|
|
10
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
11
|
+
return (
|
|
12
|
+
<ScrollAreaPrimitive.Root
|
|
13
|
+
className={cn('relative', className)}
|
|
14
|
+
data-slot="scroll-area"
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<ScrollAreaPrimitive.Viewport
|
|
18
|
+
className="size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
|
19
|
+
data-slot="scroll-area-viewport"
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</ScrollAreaPrimitive.Viewport>
|
|
23
|
+
<ScrollBar />
|
|
24
|
+
<ScrollAreaPrimitive.Corner />
|
|
25
|
+
</ScrollAreaPrimitive.Root>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ScrollBar({
|
|
30
|
+
className,
|
|
31
|
+
orientation = 'vertical',
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
|
34
|
+
return (
|
|
35
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
36
|
+
className={cn(
|
|
37
|
+
'flex touch-none select-none p-px transition-colors',
|
|
38
|
+
orientation === 'vertical' &&
|
|
39
|
+
'h-full w-2.5 border-l border-l-transparent',
|
|
40
|
+
orientation === 'horizontal' &&
|
|
41
|
+
'h-2.5 flex-col border-t border-t-transparent',
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
data-slot="scroll-area-scrollbar"
|
|
45
|
+
orientation={orientation}
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
49
|
+
className="relative flex-1 rounded-full bg-border"
|
|
50
|
+
data-slot="scroll-area-thumb"
|
|
51
|
+
/>
|
|
52
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { ScrollArea, ScrollBar };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
2
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
|
|
7
|
+
function Select({
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
10
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function SelectGroup({
|
|
14
|
+
...props
|
|
15
|
+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
16
|
+
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function SelectValue({
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
22
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function SelectTrigger({
|
|
26
|
+
className,
|
|
27
|
+
size = 'default',
|
|
28
|
+
children,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
31
|
+
size?: 'sm' | 'default';
|
|
32
|
+
}) {
|
|
33
|
+
return (
|
|
34
|
+
<SelectPrimitive.Trigger
|
|
35
|
+
className={cn(
|
|
36
|
+
"flex w-fit items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[size=default]:h-9 data-[size=sm]:h-8 data-[placeholder]:text-muted-foreground *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:hover:bg-input/50 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
37
|
+
className
|
|
38
|
+
)}
|
|
39
|
+
data-size={size}
|
|
40
|
+
data-slot="select-trigger"
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
<SelectPrimitive.Icon asChild>
|
|
45
|
+
<ChevronDownIcon className="size-4 opacity-50" />
|
|
46
|
+
</SelectPrimitive.Icon>
|
|
47
|
+
</SelectPrimitive.Trigger>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function SelectContent({
|
|
52
|
+
className,
|
|
53
|
+
children,
|
|
54
|
+
position = 'item-aligned',
|
|
55
|
+
align = 'center',
|
|
56
|
+
...props
|
|
57
|
+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
58
|
+
return (
|
|
59
|
+
<SelectPrimitive.Portal>
|
|
60
|
+
<SelectPrimitive.Content
|
|
61
|
+
align={align}
|
|
62
|
+
className={cn(
|
|
63
|
+
'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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
|
|
64
|
+
position === 'popper' &&
|
|
65
|
+
'data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1',
|
|
66
|
+
className
|
|
67
|
+
)}
|
|
68
|
+
data-slot="select-content"
|
|
69
|
+
position={position}
|
|
70
|
+
{...props}
|
|
71
|
+
>
|
|
72
|
+
<SelectScrollUpButton />
|
|
73
|
+
<SelectPrimitive.Viewport
|
|
74
|
+
className={cn(
|
|
75
|
+
'p-1',
|
|
76
|
+
position === 'popper' &&
|
|
77
|
+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1'
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</SelectPrimitive.Viewport>
|
|
82
|
+
<SelectScrollDownButton />
|
|
83
|
+
</SelectPrimitive.Content>
|
|
84
|
+
</SelectPrimitive.Portal>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function SelectLabel({
|
|
89
|
+
className,
|
|
90
|
+
...props
|
|
91
|
+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
92
|
+
return (
|
|
93
|
+
<SelectPrimitive.Label
|
|
94
|
+
className={cn('px-2 py-1.5 text-muted-foreground text-xs', className)}
|
|
95
|
+
data-slot="select-label"
|
|
96
|
+
{...props}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function SelectItem({
|
|
102
|
+
className,
|
|
103
|
+
children,
|
|
104
|
+
...props
|
|
105
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
106
|
+
return (
|
|
107
|
+
<SelectPrimitive.Item
|
|
108
|
+
className={cn(
|
|
109
|
+
"relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
110
|
+
className
|
|
111
|
+
)}
|
|
112
|
+
data-slot="select-item"
|
|
113
|
+
{...props}
|
|
114
|
+
>
|
|
115
|
+
<span
|
|
116
|
+
className="absolute right-2 flex size-3.5 items-center justify-center"
|
|
117
|
+
data-slot="select-item-indicator"
|
|
118
|
+
>
|
|
119
|
+
<SelectPrimitive.ItemIndicator>
|
|
120
|
+
<CheckIcon className="size-4" />
|
|
121
|
+
</SelectPrimitive.ItemIndicator>
|
|
122
|
+
</span>
|
|
123
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
124
|
+
</SelectPrimitive.Item>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function SelectSeparator({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
132
|
+
return (
|
|
133
|
+
<SelectPrimitive.Separator
|
|
134
|
+
className={cn('pointer-events-none -mx-1 my-1 h-px bg-border', className)}
|
|
135
|
+
data-slot="select-separator"
|
|
136
|
+
{...props}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function SelectScrollUpButton({
|
|
142
|
+
className,
|
|
143
|
+
...props
|
|
144
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
145
|
+
return (
|
|
146
|
+
<SelectPrimitive.ScrollUpButton
|
|
147
|
+
className={cn(
|
|
148
|
+
'flex cursor-default items-center justify-center py-1',
|
|
149
|
+
className
|
|
150
|
+
)}
|
|
151
|
+
data-slot="select-scroll-up-button"
|
|
152
|
+
{...props}
|
|
153
|
+
>
|
|
154
|
+
<ChevronUpIcon className="size-4" />
|
|
155
|
+
</SelectPrimitive.ScrollUpButton>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function SelectScrollDownButton({
|
|
160
|
+
className,
|
|
161
|
+
...props
|
|
162
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
163
|
+
return (
|
|
164
|
+
<SelectPrimitive.ScrollDownButton
|
|
165
|
+
className={cn(
|
|
166
|
+
'flex cursor-default items-center justify-center py-1',
|
|
167
|
+
className
|
|
168
|
+
)}
|
|
169
|
+
data-slot="select-scroll-down-button"
|
|
170
|
+
{...props}
|
|
171
|
+
>
|
|
172
|
+
<ChevronDownIcon className="size-4" />
|
|
173
|
+
</SelectPrimitive.ScrollDownButton>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
Select,
|
|
179
|
+
SelectContent,
|
|
180
|
+
SelectGroup,
|
|
181
|
+
SelectItem,
|
|
182
|
+
SelectLabel,
|
|
183
|
+
SelectScrollDownButton,
|
|
184
|
+
SelectScrollUpButton,
|
|
185
|
+
SelectSeparator,
|
|
186
|
+
SelectTrigger,
|
|
187
|
+
SelectValue,
|
|
188
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
function Separator({
|
|
7
|
+
className,
|
|
8
|
+
orientation = 'horizontal',
|
|
9
|
+
decorative = true,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
|
12
|
+
return (
|
|
13
|
+
<SeparatorPrimitive.Root
|
|
14
|
+
className={cn(
|
|
15
|
+
'shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px',
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
data-slot="separator"
|
|
19
|
+
decorative={decorative}
|
|
20
|
+
orientation={orientation}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { Separator };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
function Table({ className, ...props }: React.ComponentProps<'table'>) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
className="relative w-full overflow-x-auto"
|
|
9
|
+
data-slot="table-container"
|
|
10
|
+
>
|
|
11
|
+
<table
|
|
12
|
+
className={cn('w-full caption-bottom text-sm', className)}
|
|
13
|
+
data-slot="table"
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) {
|
|
21
|
+
return (
|
|
22
|
+
<thead
|
|
23
|
+
className={cn('[&_tr]:border-b', className)}
|
|
24
|
+
data-slot="table-header"
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) {
|
|
31
|
+
return (
|
|
32
|
+
<tbody
|
|
33
|
+
className={cn('[&_tr:last-child]:border-0', className)}
|
|
34
|
+
data-slot="table-body"
|
|
35
|
+
{...props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) {
|
|
41
|
+
return (
|
|
42
|
+
<tfoot
|
|
43
|
+
className={cn(
|
|
44
|
+
'border-t bg-muted/50 font-medium [&>tr]:last:border-b-0',
|
|
45
|
+
className
|
|
46
|
+
)}
|
|
47
|
+
data-slot="table-footer"
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function TableRow({ className, ...props }: React.ComponentProps<'tr'>) {
|
|
54
|
+
return (
|
|
55
|
+
<tr
|
|
56
|
+
className={cn(
|
|
57
|
+
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
|
58
|
+
className
|
|
59
|
+
)}
|
|
60
|
+
data-slot="table-row"
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
|
|
67
|
+
return (
|
|
68
|
+
<th
|
|
69
|
+
className={cn(
|
|
70
|
+
'h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
|
|
71
|
+
className
|
|
72
|
+
)}
|
|
73
|
+
data-slot="table-head"
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
|
|
80
|
+
return (
|
|
81
|
+
<td
|
|
82
|
+
className={cn(
|
|
83
|
+
'whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
|
|
84
|
+
className
|
|
85
|
+
)}
|
|
86
|
+
data-slot="table-cell"
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function TableCaption({
|
|
93
|
+
className,
|
|
94
|
+
...props
|
|
95
|
+
}: React.ComponentProps<'caption'>) {
|
|
96
|
+
return (
|
|
97
|
+
<caption
|
|
98
|
+
className={cn('mt-4 text-muted-foreground text-sm', className)}
|
|
99
|
+
data-slot="table-caption"
|
|
100
|
+
{...props}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
Table,
|
|
107
|
+
TableHeader,
|
|
108
|
+
TableBody,
|
|
109
|
+
TableFooter,
|
|
110
|
+
TableHead,
|
|
111
|
+
TableRow,
|
|
112
|
+
TableCell,
|
|
113
|
+
TableCaption,
|
|
114
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|
6
|
+
return (
|
|
7
|
+
<textarea
|
|
8
|
+
className={cn(
|
|
9
|
+
'field-sizing-content flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs outline-none transition-[color,box-shadow] placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40',
|
|
10
|
+
className
|
|
11
|
+
)}
|
|
12
|
+
data-slot="textarea"
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { Textarea };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
function TooltipProvider({
|
|
7
|
+
delayDuration = 0,
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
10
|
+
return (
|
|
11
|
+
<TooltipPrimitive.Provider
|
|
12
|
+
data-slot="tooltip-provider"
|
|
13
|
+
delayDuration={delayDuration}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function Tooltip({
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
22
|
+
return (
|
|
23
|
+
<TooltipProvider>
|
|
24
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
</TooltipProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function TooltipTrigger({
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
32
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function TooltipContent({
|
|
36
|
+
className,
|
|
37
|
+
sideOffset = 0,
|
|
38
|
+
children,
|
|
39
|
+
...props
|
|
40
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
41
|
+
return (
|
|
42
|
+
<TooltipPrimitive.Portal>
|
|
43
|
+
<TooltipPrimitive.Content
|
|
44
|
+
className={cn(
|
|
45
|
+
'fade-in-0 zoom-in-95 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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in text-balance rounded-md bg-foreground px-3 py-1.5 text-background text-xs data-[state=closed]:animate-out',
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
data-slot="tooltip-content"
|
|
49
|
+
sideOffset={sideOffset}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
|
54
|
+
</TooltipPrimitive.Content>
|
|
55
|
+
</TooltipPrimitive.Portal>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* =============================================================================
|
|
4
|
+
GNO Serve - "Scholarly Dusk" Design System
|
|
5
|
+
Matching the website design language for consistency
|
|
6
|
+
============================================================================= */
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
/* Dark theme (Default) - "Library at Night" */
|
|
10
|
+
--background: 0 0% 2%; /* #050505 */
|
|
11
|
+
--foreground: 0 0% 93%; /* #ededed */
|
|
12
|
+
--card: 220 14% 7%; /* #0f1115 */
|
|
13
|
+
--card-foreground: 0 0% 93%;
|
|
14
|
+
--popover: 220 14% 7%;
|
|
15
|
+
--popover-foreground: 0 0% 93%;
|
|
16
|
+
--primary: 169 41% 51%; /* #4db8a8 - Alchemical Teal */
|
|
17
|
+
--primary-foreground: 0 0% 100%;
|
|
18
|
+
--secondary: 39 56% 58%; /* #d4a053 - Old Gold */
|
|
19
|
+
--secondary-foreground: 0 0% 100%;
|
|
20
|
+
--muted: 217 14% 11%; /* #181b21 */
|
|
21
|
+
--muted-foreground: 214 7% 61%; /* #949ba3 */
|
|
22
|
+
--accent: 169 41% 51%;
|
|
23
|
+
--accent-foreground: 0 0% 100%;
|
|
24
|
+
--destructive: 0 84% 60%;
|
|
25
|
+
--destructive-foreground: 0 0% 100%;
|
|
26
|
+
--border: 216 12% 14%; /* #1f2329 */
|
|
27
|
+
--input: 216 12% 14%;
|
|
28
|
+
--ring: 169 41% 51%;
|
|
29
|
+
--radius: 0.5rem;
|
|
30
|
+
|
|
31
|
+
/* Extended palette */
|
|
32
|
+
--surface: 217 14% 11%;
|
|
33
|
+
--hover: 217 12% 16%;
|
|
34
|
+
--accent-glow: 169 41% 51%;
|
|
35
|
+
--warm: 39 56% 58%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[data-theme="light"] {
|
|
39
|
+
/* Light theme - "Antique Paper" */
|
|
40
|
+
--background: 40 33% 98%; /* #fcfbf9 */
|
|
41
|
+
--foreground: 30 9% 13%; /* #24221f */
|
|
42
|
+
--card: 38 24% 95%; /* #f5f2ee */
|
|
43
|
+
--card-foreground: 30 9% 13%;
|
|
44
|
+
--popover: 38 24% 95%;
|
|
45
|
+
--popover-foreground: 30 9% 13%;
|
|
46
|
+
--primary: 191 66% 32%; /* #1a6b7d */
|
|
47
|
+
--primary-foreground: 0 0% 100%;
|
|
48
|
+
--secondary: 39 62% 35%; /* #9a7225 */
|
|
49
|
+
--secondary-foreground: 0 0% 100%;
|
|
50
|
+
--muted: 35 17% 91%;
|
|
51
|
+
--muted-foreground: 30 8% 33%;
|
|
52
|
+
--border: 35 12% 85%;
|
|
53
|
+
--input: 35 12% 85%;
|
|
54
|
+
--ring: 191 66% 32%;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Base styles */
|
|
58
|
+
* {
|
|
59
|
+
border-color: hsl(var(--border));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
html {
|
|
63
|
+
font-size: 16px;
|
|
64
|
+
scroll-behavior: smooth;
|
|
65
|
+
-webkit-font-smoothing: antialiased;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
body {
|
|
69
|
+
/* System fonts for local-first/offline operation */
|
|
70
|
+
font-family:
|
|
71
|
+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
72
|
+
background-color: hsl(var(--background));
|
|
73
|
+
color: hsl(var(--foreground));
|
|
74
|
+
line-height: 1.65;
|
|
75
|
+
margin: 0;
|
|
76
|
+
min-height: 100vh;
|
|
77
|
+
|
|
78
|
+
/* Subtle grid pattern */
|
|
79
|
+
background-image:
|
|
80
|
+
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
|
|
81
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
|
|
82
|
+
background-size: 40px 40px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
::selection {
|
|
86
|
+
background-color: hsl(var(--primary) / 0.15);
|
|
87
|
+
color: hsl(var(--primary));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Typography */
|
|
91
|
+
h1,
|
|
92
|
+
h2,
|
|
93
|
+
h3,
|
|
94
|
+
h4,
|
|
95
|
+
h5,
|
|
96
|
+
h6 {
|
|
97
|
+
/* System serif for local-first/offline operation */
|
|
98
|
+
font-family: Georgia, "Times New Roman", serif;
|
|
99
|
+
line-height: 1.25;
|
|
100
|
+
font-weight: 600;
|
|
101
|
+
letter-spacing: -0.01em;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
code,
|
|
105
|
+
pre {
|
|
106
|
+
font-family:
|
|
107
|
+
"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
108
|
+
monospace;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Search highlight */
|
|
112
|
+
mark {
|
|
113
|
+
@apply bg-yellow-500/30 text-inherit rounded-sm px-0.5;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Focus styles */
|
|
117
|
+
:focus-visible {
|
|
118
|
+
outline: 2px solid hsl(var(--primary));
|
|
119
|
+
outline-offset: 2px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
:focus:not(:focus-visible) {
|
|
123
|
+
outline: none;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Custom scrollbar */
|
|
127
|
+
::-webkit-scrollbar {
|
|
128
|
+
width: 8px;
|
|
129
|
+
height: 8px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
::-webkit-scrollbar-track {
|
|
133
|
+
background: transparent;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
::-webkit-scrollbar-thumb {
|
|
137
|
+
background: hsl(var(--border));
|
|
138
|
+
border-radius: 4px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
::-webkit-scrollbar-thumb:hover {
|
|
142
|
+
background: hsl(var(--muted-foreground) / 0.5);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Animation utilities */
|
|
146
|
+
@keyframes fade-in {
|
|
147
|
+
from {
|
|
148
|
+
opacity: 0;
|
|
149
|
+
transform: translateY(10px);
|
|
150
|
+
}
|
|
151
|
+
to {
|
|
152
|
+
opacity: 1;
|
|
153
|
+
transform: translateY(0);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@keyframes pulse-glow {
|
|
158
|
+
0%,
|
|
159
|
+
100% {
|
|
160
|
+
box-shadow: 0 0 20px hsl(var(--primary) / 0.2);
|
|
161
|
+
}
|
|
162
|
+
50% {
|
|
163
|
+
box-shadow: 0 0 40px hsl(var(--primary) / 0.4);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.animate-fade-in {
|
|
168
|
+
animation: fade-in 0.5s ease-out forwards;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.animate-pulse-glow {
|
|
172
|
+
animation: pulse-glow 3s ease-in-out infinite;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Stagger animation delays */
|
|
176
|
+
.stagger-1 {
|
|
177
|
+
animation-delay: 0.1s;
|
|
178
|
+
}
|
|
179
|
+
.stagger-2 {
|
|
180
|
+
animation-delay: 0.2s;
|
|
181
|
+
}
|
|
182
|
+
.stagger-3 {
|
|
183
|
+
animation-delay: 0.3s;
|
|
184
|
+
}
|
|
185
|
+
.stagger-4 {
|
|
186
|
+
animation-delay: 0.4s;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Glassmorphism utility */
|
|
190
|
+
.glass {
|
|
191
|
+
background: hsl(var(--background) / 0.8);
|
|
192
|
+
backdrop-filter: blur(16px);
|
|
193
|
+
-webkit-backdrop-filter: blur(16px);
|
|
194
|
+
border: 1px solid hsl(var(--border) / 0.5);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Aurora glow effect */
|
|
198
|
+
.aurora-glow {
|
|
199
|
+
position: relative;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.aurora-glow::before {
|
|
203
|
+
content: "";
|
|
204
|
+
position: absolute;
|
|
205
|
+
inset: -50%;
|
|
206
|
+
background: radial-gradient(
|
|
207
|
+
ellipse at center,
|
|
208
|
+
hsl(var(--primary) / 0.15),
|
|
209
|
+
transparent 70%
|
|
210
|
+
);
|
|
211
|
+
z-index: -1;
|
|
212
|
+
pointer-events: none;
|
|
213
|
+
filter: blur(60px);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Reduced motion support */
|
|
217
|
+
@media (prefers-reduced-motion: reduce) {
|
|
218
|
+
*,
|
|
219
|
+
*::before,
|
|
220
|
+
*::after {
|
|
221
|
+
animation-duration: 0.01ms !important;
|
|
222
|
+
animation-iteration-count: 1 !important;
|
|
223
|
+
transition-duration: 0.01ms !important;
|
|
224
|
+
scroll-behavior: auto !important;
|
|
225
|
+
}
|
|
226
|
+
}
|