@epicbagel/saas-kit 1.25.1 → 1.27.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 +50 -0
- package/dist/chunk-DHXKCMKY.cjs +198 -0
- package/dist/chunk-HO6DRDGD.js +158 -0
- package/dist/chunk-NXFZULS3.js +58 -0
- package/dist/chunk-SG4ZE2EN.js +198 -0
- package/dist/chunk-U7XNNLVP.cjs +58 -0
- package/dist/chunk-ZBWL7OUW.cjs +158 -0
- package/dist/primitives/board-view.cjs +3 -3
- package/dist/primitives/board-view.js +2 -2
- package/dist/primitives/chat-turn-navigator.cjs +16 -0
- package/dist/primitives/chat-turn-navigator.d.cts +40 -0
- package/dist/primitives/chat-turn-navigator.d.ts +40 -0
- package/dist/primitives/chat-turn-navigator.js +16 -0
- package/dist/primitives/chat.cjs +175 -20
- package/dist/primitives/chat.d.cts +78 -1
- package/dist/primitives/chat.d.ts +78 -1
- package/dist/primitives/chat.js +167 -12
- package/dist/primitives/item.cjs +24 -194
- package/dist/primitives/item.js +13 -183
- package/dist/primitives/notes.cjs +3 -3
- package/dist/primitives/notes.js +3 -3
- package/dist/primitives/person-avatar.cjs +4 -50
- package/dist/primitives/person-avatar.js +5 -51
- package/dist/primitives/resource-list.cjs +3 -3
- package/dist/primitives/resource-list.js +2 -2
- package/package.json +11 -1
- package/dist/{chunk-LQPJGZIE.js → chunk-JS6BLIWL.js} +3 -3
- package/dist/{chunk-FBVZRRA4.cjs → chunk-MOJHETNO.cjs} +2 -2
package/README.md
CHANGED
|
@@ -543,6 +543,56 @@ Inside a `MessageScrollerProvider`, use `MessageScrollerNavigator` from
|
|
|
543
543
|
`primitives/message-scroller` with the same props. It uses the thread's scroll
|
|
544
544
|
controller so incoming messages do not undo a jump into a long list.
|
|
545
545
|
|
|
546
|
+
### Moving through a conversation (1.26.0)
|
|
547
|
+
|
|
548
|
+
`Chat` and `ChatThread` take `navigator`: an array of `ChatNavigatorItem`.
|
|
549
|
+
Each item has a `messageId` from the thread and a `title`, plus an optional
|
|
550
|
+
`excerpt` and `kind` ("Plan", "Summary").
|
|
551
|
+
|
|
552
|
+
`ChatTurnNavigator` draws them as a rail of short ticks in the thread's gutter.
|
|
553
|
+
- **Which tick is marked:** the one for the place in view, read from the
|
|
554
|
+
scroller's own visibility tracking (`activeNavigatorItem`).
|
|
555
|
+
- **Preview:** hovering or focusing a tick shows its kind, title and excerpt.
|
|
556
|
+
- **Jump:** clicking scrolls through the thread's anchoring, as
|
|
557
|
+
`MessageScrollerNavigator` does.
|
|
558
|
+
- **Keyboard:** arrow keys, Home and End move between ticks, and the rail is
|
|
559
|
+
one tab stop.
|
|
560
|
+
- **Placement:** the start gutter by default, or `navigatorSide="end"`, under
|
|
561
|
+
`navigatorLabel` (default "Conversation"). The rail only shows where the
|
|
562
|
+
gutter beside the reading column has room, so it stays out of a narrow
|
|
563
|
+
thread or a phone.
|
|
564
|
+
|
|
565
|
+
`ChatMessage.author` (`{ id, name, avatarUrl?, detail? }`) names who wrote a
|
|
566
|
+
turn. The thread draws the avatar and name above the first of each run of
|
|
567
|
+
turns by the same person on the same side, and again after a time marker, so
|
|
568
|
+
a conversation with several people in it says who said what.
|
|
569
|
+
|
|
570
|
+
### Next steps in the empty state (1.27.0)
|
|
571
|
+
|
|
572
|
+
`Chat` takes `emptyActions`, an array of `ChatEmptyAction`: what a returning
|
|
573
|
+
user can pick up, shown under the empty-state composer and before any
|
|
574
|
+
`examplePrompts`.
|
|
575
|
+
|
|
576
|
+
```tsx
|
|
577
|
+
<Chat
|
|
578
|
+
messages={[]}
|
|
579
|
+
onSend={send}
|
|
580
|
+
emptyActions={[
|
|
581
|
+
{ id: "review", icon: Users, label: "Review 3 new people", detail: "Head of Sales · Northwind", onSelect: openReview },
|
|
582
|
+
{ id: "answer", icon: MessageCircleQuestion, label: "London", detail: "Where is the role based? · VP Finance", onSelect: answer },
|
|
583
|
+
]}
|
|
584
|
+
/>
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
- **A row** is a button: the icon, the `label` and the muted `detail`, on one
|
|
588
|
+
line where there is room.
|
|
589
|
+
- **A pick** calls `onSelect` and sends nothing. Return a promise to show the
|
|
590
|
+
row's spinner and disable every row until it settles; a rejection
|
|
591
|
+
re-enables them and goes to `onSendError` (else `reportError`).
|
|
592
|
+
- **The heading** is `emptyActionsLabel`, default "Pick up where you left
|
|
593
|
+
off". `""` hides it and keeps the default as the list's accessible name.
|
|
594
|
+
- It hides while `pending` and once the conversation has started.
|
|
595
|
+
|
|
546
596
|
## Notes
|
|
547
597
|
|
|
548
598
|
`primitives/notes` provides a reusable `Notes` area and `NoteComposer` for any
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkNQK5ZWC7cjs = require('./chunk-NQK5ZWC7.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
|
|
8
|
+
|
|
9
|
+
// src/primitives/item.tsx
|
|
10
|
+
var _classvarianceauthority = require('class-variance-authority');
|
|
11
|
+
var _radixui = require('radix-ui');
|
|
12
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
13
|
+
function ItemGroup({ className, ...props }) {
|
|
14
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
15
|
+
"div",
|
|
16
|
+
{
|
|
17
|
+
role: "list",
|
|
18
|
+
"data-slot": "item-group",
|
|
19
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
20
|
+
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
|
|
21
|
+
className
|
|
22
|
+
),
|
|
23
|
+
...props
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function ItemSeparator({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}) {
|
|
31
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
32
|
+
_chunkNQK5ZWC7cjs.Separator,
|
|
33
|
+
{
|
|
34
|
+
"data-slot": "item-separator",
|
|
35
|
+
orientation: "horizontal",
|
|
36
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "my-2", className),
|
|
37
|
+
...props
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
var itemVariants = _classvarianceauthority.cva.call(void 0,
|
|
42
|
+
"group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
|
|
43
|
+
{
|
|
44
|
+
variants: {
|
|
45
|
+
variant: {
|
|
46
|
+
default: "border-transparent",
|
|
47
|
+
outline: "border-border",
|
|
48
|
+
muted: "border-transparent bg-muted/50"
|
|
49
|
+
},
|
|
50
|
+
size: {
|
|
51
|
+
default: "gap-3.5 px-4 py-3.5",
|
|
52
|
+
sm: "gap-2.5 px-3 py-2.5",
|
|
53
|
+
xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
defaultVariants: {
|
|
57
|
+
variant: "default",
|
|
58
|
+
size: "default"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
function Item({
|
|
63
|
+
className,
|
|
64
|
+
variant = "default",
|
|
65
|
+
size = "default",
|
|
66
|
+
asChild = false,
|
|
67
|
+
...props
|
|
68
|
+
}) {
|
|
69
|
+
const Comp = asChild ? _radixui.Slot.Root : "div";
|
|
70
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
71
|
+
Comp,
|
|
72
|
+
{
|
|
73
|
+
"data-slot": "item",
|
|
74
|
+
"data-variant": variant,
|
|
75
|
+
"data-size": size,
|
|
76
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, itemVariants({ variant, size, className })),
|
|
77
|
+
...props
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
var itemMediaVariants = _classvarianceauthority.cva.call(void 0,
|
|
82
|
+
"flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
|
|
83
|
+
{
|
|
84
|
+
variants: {
|
|
85
|
+
variant: {
|
|
86
|
+
default: "bg-transparent",
|
|
87
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
88
|
+
image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: {
|
|
92
|
+
variant: "default"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
function ItemMedia({
|
|
97
|
+
className,
|
|
98
|
+
variant = "default",
|
|
99
|
+
...props
|
|
100
|
+
}) {
|
|
101
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
"data-slot": "item-media",
|
|
105
|
+
"data-variant": variant,
|
|
106
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, itemMediaVariants({ variant, className })),
|
|
107
|
+
...props
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function ItemContent({ className, ...props }) {
|
|
112
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
113
|
+
"div",
|
|
114
|
+
{
|
|
115
|
+
"data-slot": "item-content",
|
|
116
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
117
|
+
"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
|
|
118
|
+
className
|
|
119
|
+
),
|
|
120
|
+
...props
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function ItemTitle({ className, ...props }) {
|
|
125
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
"data-slot": "item-title",
|
|
129
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
130
|
+
"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
|
|
131
|
+
className
|
|
132
|
+
),
|
|
133
|
+
...props
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
function ItemDescription({ className, ...props }) {
|
|
138
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
139
|
+
"p",
|
|
140
|
+
{
|
|
141
|
+
"data-slot": "item-description",
|
|
142
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
143
|
+
"line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
|
|
144
|
+
className
|
|
145
|
+
),
|
|
146
|
+
...props
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function ItemActions({ className, ...props }) {
|
|
151
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
"data-slot": "item-actions",
|
|
155
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex items-center gap-2", className),
|
|
156
|
+
...props
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function ItemHeader({ className, ...props }) {
|
|
161
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
162
|
+
"div",
|
|
163
|
+
{
|
|
164
|
+
"data-slot": "item-header",
|
|
165
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
166
|
+
"flex basis-full items-center justify-between gap-2",
|
|
167
|
+
className
|
|
168
|
+
),
|
|
169
|
+
...props
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
function ItemFooter({ className, ...props }) {
|
|
174
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
175
|
+
"div",
|
|
176
|
+
{
|
|
177
|
+
"data-slot": "item-footer",
|
|
178
|
+
className: _chunkKWLSBTB2cjs.cn.call(void 0,
|
|
179
|
+
"flex basis-full items-center justify-between gap-2",
|
|
180
|
+
className
|
|
181
|
+
),
|
|
182
|
+
...props
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
exports.ItemGroup = ItemGroup; exports.ItemSeparator = ItemSeparator; exports.Item = Item; exports.ItemMedia = ItemMedia; exports.ItemContent = ItemContent; exports.ItemTitle = ItemTitle; exports.ItemDescription = ItemDescription; exports.ItemActions = ItemActions; exports.ItemHeader = ItemHeader; exports.ItemFooter = ItemFooter;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useMessageScroller,
|
|
4
|
+
useMessageScrollerVisibility
|
|
5
|
+
} from "./chunk-OUZSIA5G.js";
|
|
6
|
+
import {
|
|
7
|
+
Tooltip,
|
|
8
|
+
TooltipContent,
|
|
9
|
+
TooltipProvider,
|
|
10
|
+
TooltipTrigger
|
|
11
|
+
} from "./chunk-ZRLUUZHK.js";
|
|
12
|
+
import {
|
|
13
|
+
cn
|
|
14
|
+
} from "./chunk-G6SRSWXB.js";
|
|
15
|
+
|
|
16
|
+
// src/primitives/chat-turn-navigator.tsx
|
|
17
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
18
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var RAIL_WIDTH = 40;
|
|
21
|
+
var RAIL_GAP = 16;
|
|
22
|
+
function activeNavigatorItem(items, order, visibleMessageIds) {
|
|
23
|
+
if (items.length === 0) return null;
|
|
24
|
+
const position = new Map(order.map((id, index) => [id, index]));
|
|
25
|
+
const firstVisible = visibleMessageIds.map((id) => position.get(id)).filter((index) => index !== void 0).sort((a, b) => a - b)[0];
|
|
26
|
+
if (firstVisible === void 0) return null;
|
|
27
|
+
let active = null;
|
|
28
|
+
for (const item of items) {
|
|
29
|
+
const index = position.get(item.messageId);
|
|
30
|
+
if (index !== void 0 && index <= firstVisible) active = item.messageId;
|
|
31
|
+
}
|
|
32
|
+
return active ?? items[0].messageId;
|
|
33
|
+
}
|
|
34
|
+
function ChatTurnNavigator({
|
|
35
|
+
items,
|
|
36
|
+
order,
|
|
37
|
+
label = "Conversation",
|
|
38
|
+
side = "start",
|
|
39
|
+
columnWidth = 768
|
|
40
|
+
}) {
|
|
41
|
+
const { scrollToMessage } = useMessageScroller();
|
|
42
|
+
const { visibleMessageIds } = useMessageScrollerVisibility();
|
|
43
|
+
const navRef = useRef(null);
|
|
44
|
+
const listRef = useRef(null);
|
|
45
|
+
const [fits, setFits] = useState(false);
|
|
46
|
+
const [focusIndex, setFocusIndex] = useState(0);
|
|
47
|
+
const active = useMemo(
|
|
48
|
+
() => activeNavigatorItem(items, order, visibleMessageIds),
|
|
49
|
+
[items, order, visibleMessageIds]
|
|
50
|
+
);
|
|
51
|
+
useLayoutEffect(() => {
|
|
52
|
+
const root = navRef.current?.parentElement;
|
|
53
|
+
if (!root) return;
|
|
54
|
+
const measure = () => setFits((root.clientWidth - columnWidth) / 2 >= RAIL_WIDTH + RAIL_GAP * 2);
|
|
55
|
+
measure();
|
|
56
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
57
|
+
const observer = new ResizeObserver(measure);
|
|
58
|
+
observer.observe(root);
|
|
59
|
+
return () => observer.disconnect();
|
|
60
|
+
}, [columnWidth]);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const list = listRef.current;
|
|
63
|
+
const index = items.findIndex((item) => item.messageId === active);
|
|
64
|
+
const tick = list?.children[index];
|
|
65
|
+
if (!list || !tick) return;
|
|
66
|
+
if (tick.offsetTop < list.scrollTop) list.scrollTop = tick.offsetTop;
|
|
67
|
+
else if (tick.offsetTop + tick.offsetHeight > list.scrollTop + list.clientHeight) {
|
|
68
|
+
list.scrollTop = tick.offsetTop + tick.offsetHeight - list.clientHeight;
|
|
69
|
+
}
|
|
70
|
+
if (index >= 0) setFocusIndex(index);
|
|
71
|
+
}, [active, items]);
|
|
72
|
+
if (items.length === 0) return null;
|
|
73
|
+
function jump(item) {
|
|
74
|
+
const reduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
75
|
+
scrollToMessage(item.messageId, { align: "start", behavior: reduced ? "instant" : "smooth", scrollMargin: 16 });
|
|
76
|
+
}
|
|
77
|
+
function onKeyDown(event, index) {
|
|
78
|
+
const next = event.key === "ArrowDown" ? index + 1 : event.key === "ArrowUp" ? index - 1 : event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : null;
|
|
79
|
+
if (next === null) return;
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
const target = Math.max(0, Math.min(items.length - 1, next));
|
|
82
|
+
setFocusIndex(target);
|
|
83
|
+
listRef.current?.children[target]?.querySelector("button")?.focus({ preventScroll: true });
|
|
84
|
+
}
|
|
85
|
+
return /* @__PURE__ */ jsx(
|
|
86
|
+
"nav",
|
|
87
|
+
{
|
|
88
|
+
ref: navRef,
|
|
89
|
+
"aria-label": label,
|
|
90
|
+
hidden: !fits,
|
|
91
|
+
"data-slot": "chat-turn-navigator",
|
|
92
|
+
className: cn(
|
|
93
|
+
"absolute top-1/2 z-10 -translate-y-1/2",
|
|
94
|
+
side === "start" ? "left-4" : "right-5"
|
|
95
|
+
),
|
|
96
|
+
children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 150, skipDelayDuration: 300, children: /* @__PURE__ */ jsx(
|
|
97
|
+
"ol",
|
|
98
|
+
{
|
|
99
|
+
ref: listRef,
|
|
100
|
+
className: "flex max-h-[60vh] flex-col overflow-y-auto py-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
101
|
+
children: items.map((item, index) => {
|
|
102
|
+
const current = item.messageId === active;
|
|
103
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
104
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
105
|
+
"button",
|
|
106
|
+
{
|
|
107
|
+
type: "button",
|
|
108
|
+
"aria-label": item.kind ? `${item.kind}: ${item.title}` : item.title,
|
|
109
|
+
"aria-current": current ? "location" : void 0,
|
|
110
|
+
tabIndex: index === focusIndex ? 0 : -1,
|
|
111
|
+
onClick: () => jump(item),
|
|
112
|
+
onKeyDown: (event) => onKeyDown(event, index),
|
|
113
|
+
className: cn(
|
|
114
|
+
"group flex h-3.5 w-10 items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
115
|
+
side === "start" ? "justify-start ps-1" : "justify-end pe-1"
|
|
116
|
+
),
|
|
117
|
+
children: /* @__PURE__ */ jsx(
|
|
118
|
+
"span",
|
|
119
|
+
{
|
|
120
|
+
"aria-hidden": true,
|
|
121
|
+
className: cn(
|
|
122
|
+
"h-0.5 rounded-full transition-[width,background-color] duration-150",
|
|
123
|
+
current ? "w-6 bg-foreground" : "w-3.5 bg-muted-foreground/45 group-hover:w-5 group-hover:bg-muted-foreground group-focus-visible:w-5"
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
) }),
|
|
129
|
+
/* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
130
|
+
TooltipContent,
|
|
131
|
+
{
|
|
132
|
+
side: side === "start" ? "right" : "left",
|
|
133
|
+
sideOffset: 10,
|
|
134
|
+
className: "flex max-w-80 flex-col gap-1 rounded-xl px-3.5 py-2.5",
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsxs("span", { className: "truncate font-medium", children: [
|
|
137
|
+
item.kind ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
138
|
+
item.kind,
|
|
139
|
+
" \xB7 "
|
|
140
|
+
] }) : null,
|
|
141
|
+
item.title
|
|
142
|
+
] }),
|
|
143
|
+
item.excerpt ? /* @__PURE__ */ jsx("span", { className: "line-clamp-3 text-xs leading-5 text-muted-foreground", children: item.excerpt }) : null
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
) })
|
|
147
|
+
] }) }, item.messageId);
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
) })
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export {
|
|
156
|
+
activeNavigatorItem,
|
|
157
|
+
ChatTurnNavigator
|
|
158
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Avatar,
|
|
4
|
+
AvatarFallback,
|
|
5
|
+
AvatarImage
|
|
6
|
+
} from "./chunk-3OWGL4Q2.js";
|
|
7
|
+
import {
|
|
8
|
+
cn
|
|
9
|
+
} from "./chunk-G6SRSWXB.js";
|
|
10
|
+
|
|
11
|
+
// src/primitives/person-avatar.tsx
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
function initials(name) {
|
|
14
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
15
|
+
const first = words[0];
|
|
16
|
+
if (!first) return "?";
|
|
17
|
+
const last = words[words.length - 1];
|
|
18
|
+
if (words.length === 1 || !last) return first.slice(0, 2).toUpperCase();
|
|
19
|
+
return (first.charAt(0) + last.charAt(0)).toUpperCase();
|
|
20
|
+
}
|
|
21
|
+
function PersonAvatar({
|
|
22
|
+
name,
|
|
23
|
+
photoUrl,
|
|
24
|
+
size,
|
|
25
|
+
className,
|
|
26
|
+
fallbackClassName,
|
|
27
|
+
fallbackSize = "default"
|
|
28
|
+
}) {
|
|
29
|
+
return /* @__PURE__ */ jsxs(
|
|
30
|
+
Avatar,
|
|
31
|
+
{
|
|
32
|
+
className: cn("shrink-0 overflow-hidden rounded-full bg-muted", className),
|
|
33
|
+
style: size != null ? { width: size, height: size } : void 0,
|
|
34
|
+
children: [
|
|
35
|
+
photoUrl ? /* @__PURE__ */ jsx(
|
|
36
|
+
AvatarImage,
|
|
37
|
+
{
|
|
38
|
+
src: photoUrl,
|
|
39
|
+
alt: name,
|
|
40
|
+
className: "h-full w-full object-cover"
|
|
41
|
+
}
|
|
42
|
+
) : null,
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
AvatarFallback,
|
|
45
|
+
{
|
|
46
|
+
className: cn("h-full w-full font-medium", fallbackSize === "default" ? "text-xs" : "text-xl", fallbackClassName),
|
|
47
|
+
children: initials(name)
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
initials,
|
|
57
|
+
PersonAvatar
|
|
58
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Separator
|
|
4
|
+
} from "./chunk-HYTILYE5.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-G6SRSWXB.js";
|
|
8
|
+
|
|
9
|
+
// src/primitives/item.tsx
|
|
10
|
+
import { cva } from "class-variance-authority";
|
|
11
|
+
import { Slot } from "radix-ui";
|
|
12
|
+
import { jsx } from "react/jsx-runtime";
|
|
13
|
+
function ItemGroup({ className, ...props }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(
|
|
15
|
+
"div",
|
|
16
|
+
{
|
|
17
|
+
role: "list",
|
|
18
|
+
"data-slot": "item-group",
|
|
19
|
+
className: cn(
|
|
20
|
+
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
|
|
21
|
+
className
|
|
22
|
+
),
|
|
23
|
+
...props
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function ItemSeparator({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}) {
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
Separator,
|
|
33
|
+
{
|
|
34
|
+
"data-slot": "item-separator",
|
|
35
|
+
orientation: "horizontal",
|
|
36
|
+
className: cn("my-2", className),
|
|
37
|
+
...props
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
var itemVariants = cva(
|
|
42
|
+
"group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
|
|
43
|
+
{
|
|
44
|
+
variants: {
|
|
45
|
+
variant: {
|
|
46
|
+
default: "border-transparent",
|
|
47
|
+
outline: "border-border",
|
|
48
|
+
muted: "border-transparent bg-muted/50"
|
|
49
|
+
},
|
|
50
|
+
size: {
|
|
51
|
+
default: "gap-3.5 px-4 py-3.5",
|
|
52
|
+
sm: "gap-2.5 px-3 py-2.5",
|
|
53
|
+
xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
defaultVariants: {
|
|
57
|
+
variant: "default",
|
|
58
|
+
size: "default"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
function Item({
|
|
63
|
+
className,
|
|
64
|
+
variant = "default",
|
|
65
|
+
size = "default",
|
|
66
|
+
asChild = false,
|
|
67
|
+
...props
|
|
68
|
+
}) {
|
|
69
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
70
|
+
return /* @__PURE__ */ jsx(
|
|
71
|
+
Comp,
|
|
72
|
+
{
|
|
73
|
+
"data-slot": "item",
|
|
74
|
+
"data-variant": variant,
|
|
75
|
+
"data-size": size,
|
|
76
|
+
className: cn(itemVariants({ variant, size, className })),
|
|
77
|
+
...props
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
var itemMediaVariants = cva(
|
|
82
|
+
"flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
|
|
83
|
+
{
|
|
84
|
+
variants: {
|
|
85
|
+
variant: {
|
|
86
|
+
default: "bg-transparent",
|
|
87
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
88
|
+
image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
defaultVariants: {
|
|
92
|
+
variant: "default"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
function ItemMedia({
|
|
97
|
+
className,
|
|
98
|
+
variant = "default",
|
|
99
|
+
...props
|
|
100
|
+
}) {
|
|
101
|
+
return /* @__PURE__ */ jsx(
|
|
102
|
+
"div",
|
|
103
|
+
{
|
|
104
|
+
"data-slot": "item-media",
|
|
105
|
+
"data-variant": variant,
|
|
106
|
+
className: cn(itemMediaVariants({ variant, className })),
|
|
107
|
+
...props
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function ItemContent({ className, ...props }) {
|
|
112
|
+
return /* @__PURE__ */ jsx(
|
|
113
|
+
"div",
|
|
114
|
+
{
|
|
115
|
+
"data-slot": "item-content",
|
|
116
|
+
className: cn(
|
|
117
|
+
"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
|
|
118
|
+
className
|
|
119
|
+
),
|
|
120
|
+
...props
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function ItemTitle({ className, ...props }) {
|
|
125
|
+
return /* @__PURE__ */ jsx(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
"data-slot": "item-title",
|
|
129
|
+
className: cn(
|
|
130
|
+
"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
|
|
131
|
+
className
|
|
132
|
+
),
|
|
133
|
+
...props
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
function ItemDescription({ className, ...props }) {
|
|
138
|
+
return /* @__PURE__ */ jsx(
|
|
139
|
+
"p",
|
|
140
|
+
{
|
|
141
|
+
"data-slot": "item-description",
|
|
142
|
+
className: cn(
|
|
143
|
+
"line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
|
|
144
|
+
className
|
|
145
|
+
),
|
|
146
|
+
...props
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function ItemActions({ className, ...props }) {
|
|
151
|
+
return /* @__PURE__ */ jsx(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
"data-slot": "item-actions",
|
|
155
|
+
className: cn("flex items-center gap-2", className),
|
|
156
|
+
...props
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function ItemHeader({ className, ...props }) {
|
|
161
|
+
return /* @__PURE__ */ jsx(
|
|
162
|
+
"div",
|
|
163
|
+
{
|
|
164
|
+
"data-slot": "item-header",
|
|
165
|
+
className: cn(
|
|
166
|
+
"flex basis-full items-center justify-between gap-2",
|
|
167
|
+
className
|
|
168
|
+
),
|
|
169
|
+
...props
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
function ItemFooter({ className, ...props }) {
|
|
174
|
+
return /* @__PURE__ */ jsx(
|
|
175
|
+
"div",
|
|
176
|
+
{
|
|
177
|
+
"data-slot": "item-footer",
|
|
178
|
+
className: cn(
|
|
179
|
+
"flex basis-full items-center justify-between gap-2",
|
|
180
|
+
className
|
|
181
|
+
),
|
|
182
|
+
...props
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
ItemGroup,
|
|
189
|
+
ItemSeparator,
|
|
190
|
+
Item,
|
|
191
|
+
ItemMedia,
|
|
192
|
+
ItemContent,
|
|
193
|
+
ItemTitle,
|
|
194
|
+
ItemDescription,
|
|
195
|
+
ItemActions,
|
|
196
|
+
ItemHeader,
|
|
197
|
+
ItemFooter
|
|
198
|
+
};
|