@papernote/ui 1.11.6 → 1.12.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/dist/components/ChatUI.d.ts +59 -0
- package/dist/components/ChatUI.d.ts.map +1 -0
- package/dist/components/InsightsPanelUI.d.ts +56 -0
- package/dist/components/InsightsPanelUI.d.ts.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +114 -2
- package/dist/index.esm.js +185 -50
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +185 -48
- package/dist/index.js.map +1 -1
- package/dist/styles.css +59 -0
- package/package.json +1 -1
- package/src/components/ChatUI.tsx +214 -0
- package/src/components/InsightsPanelUI.tsx +244 -0
- package/src/components/index.ts +6 -0
package/dist/index.js
CHANGED
|
@@ -5418,7 +5418,7 @@ function SharedBadge({ sharedWith, variant, size = 'md', maxDisplay = 3, onClick
|
|
|
5418
5418
|
}
|
|
5419
5419
|
|
|
5420
5420
|
// Format relative time
|
|
5421
|
-
function formatRelativeTime$
|
|
5421
|
+
function formatRelativeTime$3(date) {
|
|
5422
5422
|
const now = new Date();
|
|
5423
5423
|
const diffMs = now.getTime() - date.getTime();
|
|
5424
5424
|
const diffMins = Math.floor(diffMs / 60000);
|
|
@@ -5450,11 +5450,11 @@ function ActivityFeed({ activities, maxItems, showTimestamps = true, onLoadMore,
|
|
|
5450
5450
|
if (activities.length === 0) {
|
|
5451
5451
|
return (jsxRuntime.jsxs("div", { className: `text-center py-8 ${className}`, children: [jsxRuntime.jsx(lucideReact.Activity, { className: "w-8 h-8 text-ink-300 mx-auto mb-2" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: "No activity yet" })] }));
|
|
5452
5452
|
}
|
|
5453
|
-
return (jsxRuntime.jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsxRuntime.jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxRuntime.jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [jsxRuntime.jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsxRuntime.jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntime.jsxs("p", { className: "text-sm text-ink-700", children: [jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsxRuntime.jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsxRuntime.jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$
|
|
5453
|
+
return (jsxRuntime.jsxs("div", { className: `${className}`, role: "feed", "aria-label": "Activity feed", children: [jsxRuntime.jsx("div", { className: "space-y-4", children: displayedActivities.map((activity, index) => (jsxRuntime.jsxs("div", { className: "flex gap-3", role: "article", "aria-label": `${activity.user.name} ${activity.action}${activity.target ? ` ${activity.target}` : ''}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [jsxRuntime.jsx(CollaboratorAvatars, { collaborators: [activity.user], max: 1, size: "sm" }), index < displayedActivities.length - 1 && (jsxRuntime.jsx("div", { className: "w-0.5 flex-1 bg-paper-200 mt-2" }))] }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 pb-4", children: jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntime.jsxs("p", { className: "text-sm text-ink-700", children: [jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.user.name }), ' ', activity.action, activity.target && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [' ', jsxRuntime.jsx("span", { className: "font-medium text-ink-800", children: activity.target })] }))] }) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [activity.icon && (jsxRuntime.jsx("span", { className: "text-ink-400", children: activity.icon })), showTimestamps && (jsxRuntime.jsx("span", { className: "text-xs text-ink-400 whitespace-nowrap", children: formatRelativeTime$3(activity.timestamp) }))] })] }) })] }, activity.id))) }), (hasMore || onLoadMore) && (jsxRuntime.jsx("div", { className: "mt-4 text-center", children: jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: onLoadMore, loading: loading, children: loading ? 'Loading...' : 'Load more' }) }))] }));
|
|
5454
5454
|
}
|
|
5455
5455
|
|
|
5456
5456
|
// Format relative time
|
|
5457
|
-
function formatRelativeTime(date) {
|
|
5457
|
+
function formatRelativeTime$2(date) {
|
|
5458
5458
|
const now = new Date();
|
|
5459
5459
|
const diffMs = now.getTime() - date.getTime();
|
|
5460
5460
|
const diffMins = Math.floor(diffMs / 60000);
|
|
@@ -5522,7 +5522,7 @@ function InviteCard({ onInvite, pending = [], loading = false, maxPending = 5, o
|
|
|
5522
5522
|
shadow-card
|
|
5523
5523
|
p-4
|
|
5524
5524
|
${className}
|
|
5525
|
-
`, children: jsxRuntime.jsxs(Stack, { gap: "md", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsxRuntime.jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsxRuntime.jsx(lucideReact.Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsxRuntime.jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx(Input, { type: "email", placeholder: "Enter email address", value: email, onChange: (e) => handleEmailChange(e.target.value), validationState: error ? 'error' : undefined, validationMessage: error || undefined, disabled: loading }) }), jsxRuntime.jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxRuntime.jsxs(Stack, { gap: "sm", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-ink-400" }), jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxRuntime.jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxRuntime.jsxs(Stack, { gap: "xs", children: [jsxRuntime.jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxRuntime.jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime(invite.sentAt)] })] }), onCancelInvite && (jsxRuntime.jsx("button", { onClick: () => onCancelInvite(invite.email), className: "p-1 rounded hover:bg-paper-100 text-ink-400 hover:text-error-500 transition-colors", "aria-label": `Cancel invitation to ${invite.email}`, children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsxRuntime.jsx("div", { className: "px-3 py-2 text-center", children: jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
|
|
5525
|
+
`, children: jsxRuntime.jsxs(Stack, { gap: "md", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", align: "center", children: [jsxRuntime.jsx("div", { className: "p-2 bg-accent-100 rounded-lg", children: jsxRuntime.jsx(lucideReact.Mail, { className: "w-5 h-5 text-accent-600" }) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text, { weight: "semibold", className: "text-ink-800", children: "Invite People" }), jsxRuntime.jsx(Text, { size: "sm", className: "text-ink-500", children: "Share access via email" })] })] }), jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "sm", children: [jsxRuntime.jsx("div", { className: "flex-1", children: jsxRuntime.jsx(Input, { type: "email", placeholder: "Enter email address", value: email, onChange: (e) => handleEmailChange(e.target.value), validationState: error ? 'error' : undefined, validationMessage: error || undefined, disabled: loading }) }), jsxRuntime.jsx(Button, { type: "submit", variant: "primary", loading: loading, disabled: !email.trim(), icon: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }), children: "Send" })] }) }), displayedPending.length > 0 && (jsxRuntime.jsxs(Stack, { gap: "sm", children: [jsxRuntime.jsxs(Stack, { direction: "horizontal", gap: "xs", align: "center", children: [jsxRuntime.jsx(lucideReact.Clock, { className: "w-4 h-4 text-ink-400" }), jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-500", children: ["Pending invitations (", pending.length, ")"] })] }), jsxRuntime.jsxs("div", { className: "border border-paper-200 rounded-lg divide-y divide-paper-200", children: [displayedPending.map((invite) => (jsxRuntime.jsxs("div", { className: "px-3 py-2 flex items-center justify-between", children: [jsxRuntime.jsxs(Stack, { gap: "xs", children: [jsxRuntime.jsx(Text, { size: "sm", weight: "medium", className: "text-ink-700", children: invite.email }), jsxRuntime.jsxs(Text, { size: "xs", className: "text-ink-400", children: ["Sent ", formatRelativeTime$2(invite.sentAt)] })] }), onCancelInvite && (jsxRuntime.jsx("button", { onClick: () => onCancelInvite(invite.email), className: "p-1 rounded hover:bg-paper-100 text-ink-400 hover:text-error-500 transition-colors", "aria-label": `Cancel invitation to ${invite.email}`, children: jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" }) }))] }, invite.email))), hasMorePending && (jsxRuntime.jsx("div", { className: "px-3 py-2 text-center", children: jsxRuntime.jsxs(Text, { size: "sm", className: "text-ink-400", children: ["+", pending.length - maxPending, " more"] }) }))] })] }))] }) }));
|
|
5526
5526
|
}
|
|
5527
5527
|
|
|
5528
5528
|
/**
|
|
@@ -15701,52 +15701,44 @@ function getAugmentedNamespace(n) {
|
|
|
15701
15701
|
* (A1, A1:C5, ...)
|
|
15702
15702
|
*/
|
|
15703
15703
|
|
|
15704
|
-
|
|
15705
|
-
var hasRequiredCollection;
|
|
15706
|
-
|
|
15707
|
-
function requireCollection () {
|
|
15708
|
-
if (hasRequiredCollection) return collection;
|
|
15709
|
-
hasRequiredCollection = 1;
|
|
15710
|
-
class Collection {
|
|
15704
|
+
let Collection$3 = class Collection {
|
|
15711
15705
|
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15706
|
+
constructor(data, refs) {
|
|
15707
|
+
if (data == null && refs == null) {
|
|
15708
|
+
this._data = [];
|
|
15709
|
+
this._refs = [];
|
|
15710
|
+
} else {
|
|
15711
|
+
if (data.length !== refs.length)
|
|
15712
|
+
throw Error('Collection: data length should match references length.');
|
|
15713
|
+
this._data = data;
|
|
15714
|
+
this._refs = refs;
|
|
15715
|
+
}
|
|
15716
|
+
}
|
|
15723
15717
|
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15718
|
+
get data() {
|
|
15719
|
+
return this._data;
|
|
15720
|
+
}
|
|
15727
15721
|
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15722
|
+
get refs() {
|
|
15723
|
+
return this._refs;
|
|
15724
|
+
}
|
|
15731
15725
|
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15726
|
+
get length() {
|
|
15727
|
+
return this._data.length;
|
|
15728
|
+
}
|
|
15735
15729
|
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15730
|
+
/**
|
|
15731
|
+
* Add data and references to this collection.
|
|
15732
|
+
* @param {{}} obj - data
|
|
15733
|
+
* @param {{}} ref - reference
|
|
15734
|
+
*/
|
|
15735
|
+
add(obj, ref) {
|
|
15736
|
+
this._data.push(obj);
|
|
15737
|
+
this._refs.push(ref);
|
|
15738
|
+
}
|
|
15739
|
+
};
|
|
15746
15740
|
|
|
15747
|
-
|
|
15748
|
-
return collection;
|
|
15749
|
-
}
|
|
15741
|
+
var collection = Collection$3;
|
|
15750
15742
|
|
|
15751
15743
|
var helpers;
|
|
15752
15744
|
var hasRequiredHelpers;
|
|
@@ -15755,7 +15747,7 @@ function requireHelpers () {
|
|
|
15755
15747
|
if (hasRequiredHelpers) return helpers;
|
|
15756
15748
|
hasRequiredHelpers = 1;
|
|
15757
15749
|
const FormulaError = requireError();
|
|
15758
|
-
const Collection =
|
|
15750
|
+
const Collection = collection;
|
|
15759
15751
|
|
|
15760
15752
|
const Types = {
|
|
15761
15753
|
NUMBER: 0,
|
|
@@ -25409,7 +25401,7 @@ var engineering = EngineeringFunctions;
|
|
|
25409
25401
|
|
|
25410
25402
|
const FormulaError$b = requireError();
|
|
25411
25403
|
const {FormulaHelpers: FormulaHelpers$8, Types: Types$6, WildCard, Address: Address$3} = requireHelpers();
|
|
25412
|
-
const Collection$2 =
|
|
25404
|
+
const Collection$2 = collection;
|
|
25413
25405
|
const H$5 = FormulaHelpers$8;
|
|
25414
25406
|
|
|
25415
25407
|
const ReferenceFunctions$1 = {
|
|
@@ -37037,7 +37029,7 @@ var parsing = {
|
|
|
37037
37029
|
const FormulaError$4 = requireError();
|
|
37038
37030
|
const {Address: Address$1} = requireHelpers();
|
|
37039
37031
|
const {Prefix: Prefix$1, Postfix: Postfix$1, Infix: Infix$1, Operators: Operators$1} = operators;
|
|
37040
|
-
const Collection$1 =
|
|
37032
|
+
const Collection$1 = collection;
|
|
37041
37033
|
const MAX_ROW$1 = 1048576, MAX_COLUMN$1 = 16384;
|
|
37042
37034
|
const {NotAllInputParsedException} = require$$4;
|
|
37043
37035
|
|
|
@@ -37799,7 +37791,7 @@ var hooks$1 = {
|
|
|
37799
37791
|
const FormulaError$2 = requireError();
|
|
37800
37792
|
const {FormulaHelpers: FormulaHelpers$1, Types, Address} = requireHelpers();
|
|
37801
37793
|
const {Prefix, Postfix, Infix, Operators} = operators;
|
|
37802
|
-
const Collection =
|
|
37794
|
+
const Collection = collection;
|
|
37803
37795
|
const MAX_ROW = 1048576, MAX_COLUMN = 16384;
|
|
37804
37796
|
|
|
37805
37797
|
let Utils$1 = class Utils {
|
|
@@ -62614,6 +62606,149 @@ function Responsive({ mobile, tablet, desktop, }) {
|
|
|
62614
62606
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: mobile || tablet || desktop });
|
|
62615
62607
|
}
|
|
62616
62608
|
|
|
62609
|
+
function formatRelativeTime$1(date) {
|
|
62610
|
+
const now = new Date();
|
|
62611
|
+
const diffMs = now.getTime() - date.getTime();
|
|
62612
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
62613
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
62614
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
62615
|
+
if (diffMins < 1)
|
|
62616
|
+
return 'Just now';
|
|
62617
|
+
if (diffMins < 60)
|
|
62618
|
+
return `${diffMins}m ago`;
|
|
62619
|
+
if (diffHours < 24)
|
|
62620
|
+
return `${diffHours}h ago`;
|
|
62621
|
+
if (diffDays < 7)
|
|
62622
|
+
return `${diffDays}d ago`;
|
|
62623
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
62624
|
+
}
|
|
62625
|
+
/**
|
|
62626
|
+
* ChatUI - Conversational chat interface component.
|
|
62627
|
+
*
|
|
62628
|
+
* Renders a scrollable message thread with user/assistant bubbles,
|
|
62629
|
+
* a typing indicator, an input bar with send button (Enter to send,
|
|
62630
|
+
* Shift+Enter for newline), and optional suggested question chips.
|
|
62631
|
+
*
|
|
62632
|
+
* @example
|
|
62633
|
+
* ```tsx
|
|
62634
|
+
* <ChatUI
|
|
62635
|
+
* messages={messages}
|
|
62636
|
+
* inputValue={input}
|
|
62637
|
+
* isLoading={loading}
|
|
62638
|
+
* onInputChange={setInput}
|
|
62639
|
+
* onSend={handleSend}
|
|
62640
|
+
* suggestedQuestions={['What are my top deals?']}
|
|
62641
|
+
* onSuggestedQuestionClick={handleQuestion}
|
|
62642
|
+
* />
|
|
62643
|
+
* ```
|
|
62644
|
+
*/
|
|
62645
|
+
const ChatUI = React.forwardRef(({ messages, inputValue, isLoading = false, placeholder = 'Ask a question...', suggestedQuestions = [], onInputChange, onSend, onSuggestedQuestionClick, messagesEndRef, height = '600px', className = '', }, ref) => {
|
|
62646
|
+
const handleKeyDown = (e) => {
|
|
62647
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
62648
|
+
e.preventDefault();
|
|
62649
|
+
if (inputValue.trim()) {
|
|
62650
|
+
onSend();
|
|
62651
|
+
}
|
|
62652
|
+
}
|
|
62653
|
+
};
|
|
62654
|
+
return (jsxRuntime.jsxs("div", { ref: ref, className: `flex flex-col bg-white rounded-lg border border-paper-200 overflow-hidden ${className}`, style: { height }, children: [jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 && !isLoading && (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center", children: [jsxRuntime.jsx(lucideReact.Bot, { className: "w-10 h-10 text-ink-300 mb-3" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: "No messages yet. Start a conversation!" })] })), messages.map((message) => (jsxRuntime.jsxs("div", { className: `flex gap-3 ${message.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`, children: [jsxRuntime.jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center ${message.role === 'user'
|
|
62655
|
+
? 'bg-primary-100 text-primary-600'
|
|
62656
|
+
: 'bg-paper-200 text-ink-500'}`, children: message.role === 'user' ? (jsxRuntime.jsx(lucideReact.User, { className: "w-4 h-4" })) : (jsxRuntime.jsx(lucideReact.Bot, { className: "w-4 h-4" })) }), jsxRuntime.jsxs("div", { className: `max-w-[75%] rounded-xl px-4 py-2.5 ${message.role === 'user'
|
|
62657
|
+
? 'bg-primary-500 text-white rounded-br-sm'
|
|
62658
|
+
: 'bg-paper-100 text-ink-800 border border-paper-200 rounded-bl-sm'}`, children: [jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-wrap", children: message.content }), jsxRuntime.jsx("p", { className: `text-[10px] mt-1 ${message.role === 'user' ? 'text-primary-200' : 'text-ink-400'}`, children: formatRelativeTime$1(message.timestamp) })] })] }, message.id))), isLoading && (jsxRuntime.jsxs("div", { className: "flex gap-3", children: [jsxRuntime.jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded-full bg-paper-200 text-ink-500 flex items-center justify-center", children: jsxRuntime.jsx(lucideReact.Bot, { className: "w-4 h-4" }) }), jsxRuntime.jsx("div", { className: "bg-paper-100 border border-paper-200 rounded-xl rounded-bl-sm px-4 py-3", children: jsxRuntime.jsxs("div", { className: "flex gap-1.5", children: [jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '0ms' } }), jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '150ms' } }), jsxRuntime.jsx("span", { className: "w-2 h-2 bg-ink-400 rounded-full animate-bounce", style: { animationDelay: '300ms' } })] }) })] })), messagesEndRef && jsxRuntime.jsx("div", { ref: messagesEndRef })] }), suggestedQuestions.length > 0 && messages.length === 0 && (jsxRuntime.jsx("div", { className: "px-4 pb-2 flex flex-wrap gap-2", children: suggestedQuestions.map((question, index) => (jsxRuntime.jsx("button", { onClick: () => onSuggestedQuestionClick?.(question), className: "text-xs px-3 py-1.5 rounded-full border border-primary-200 text-primary-700 bg-primary-50 hover:bg-primary-100 transition-colors", children: question }, index))) })), jsxRuntime.jsx("div", { className: "border-t border-paper-200 p-3 bg-paper-50", children: jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [jsxRuntime.jsx("textarea", { value: inputValue, onChange: (e) => onInputChange(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, rows: 1, className: "flex-1 resize-none rounded-lg border border-paper-300 bg-white px-3 py-2 text-sm text-ink-800 placeholder:text-ink-400 focus:outline-none focus:ring-2 focus:ring-primary-300 focus:border-primary-300" }), jsxRuntime.jsx("button", { onClick: onSend, disabled: !inputValue.trim() || isLoading, className: "flex-shrink-0 p-2 rounded-lg bg-primary-500 text-white hover:bg-primary-600 disabled:opacity-40 disabled:cursor-not-allowed transition-colors", "aria-label": "Send message", children: jsxRuntime.jsx(lucideReact.Send, { className: "w-4 h-4" }) })] }) })] }));
|
|
62659
|
+
});
|
|
62660
|
+
ChatUI.displayName = 'ChatUI';
|
|
62661
|
+
|
|
62662
|
+
const FILTER_OPTIONS = [
|
|
62663
|
+
{ key: 'all', label: 'All' },
|
|
62664
|
+
{ key: 'trend', label: 'Trends' },
|
|
62665
|
+
{ key: 'anomaly', label: 'Anomalies' },
|
|
62666
|
+
{ key: 'forecast', label: 'Forecasts' },
|
|
62667
|
+
{ key: 'recommendation', label: 'Recommendations' },
|
|
62668
|
+
];
|
|
62669
|
+
function getTypeIcon(type) {
|
|
62670
|
+
switch (type) {
|
|
62671
|
+
case 'trend':
|
|
62672
|
+
return jsxRuntime.jsx(lucideReact.TrendingUp, { className: "w-4 h-4 text-green-600" });
|
|
62673
|
+
case 'anomaly':
|
|
62674
|
+
return jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "w-4 h-4 text-red-600" });
|
|
62675
|
+
case 'forecast':
|
|
62676
|
+
return jsxRuntime.jsx(lucideReact.Target, { className: "w-4 h-4 text-purple-600" });
|
|
62677
|
+
case 'recommendation':
|
|
62678
|
+
return jsxRuntime.jsx(lucideReact.Lightbulb, { className: "w-4 h-4 text-amber-600" });
|
|
62679
|
+
}
|
|
62680
|
+
}
|
|
62681
|
+
function getTypeBgColor(type) {
|
|
62682
|
+
switch (type) {
|
|
62683
|
+
case 'trend': return 'bg-green-50';
|
|
62684
|
+
case 'anomaly': return 'bg-red-50';
|
|
62685
|
+
case 'forecast': return 'bg-purple-50';
|
|
62686
|
+
case 'recommendation': return 'bg-amber-50';
|
|
62687
|
+
}
|
|
62688
|
+
}
|
|
62689
|
+
function getConfidenceBadge(confidence) {
|
|
62690
|
+
const pct = Math.round(confidence * 100);
|
|
62691
|
+
let colorClasses;
|
|
62692
|
+
if (confidence >= 0.8) {
|
|
62693
|
+
colorClasses = 'bg-green-100 text-green-700';
|
|
62694
|
+
}
|
|
62695
|
+
else if (confidence >= 0.6) {
|
|
62696
|
+
colorClasses = 'bg-yellow-100 text-yellow-700';
|
|
62697
|
+
}
|
|
62698
|
+
else {
|
|
62699
|
+
colorClasses = 'bg-red-100 text-red-700';
|
|
62700
|
+
}
|
|
62701
|
+
return (jsxRuntime.jsxs("span", { className: `inline-flex items-center text-[10px] font-medium px-1.5 py-0.5 rounded-full ${colorClasses}`, children: [pct, "%"] }));
|
|
62702
|
+
}
|
|
62703
|
+
function formatRelativeTime(date) {
|
|
62704
|
+
const now = new Date();
|
|
62705
|
+
const diffMs = now.getTime() - date.getTime();
|
|
62706
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
62707
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
62708
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
62709
|
+
if (diffMins < 1)
|
|
62710
|
+
return 'Just now';
|
|
62711
|
+
if (diffMins < 60)
|
|
62712
|
+
return `${diffMins}m ago`;
|
|
62713
|
+
if (diffHours < 24)
|
|
62714
|
+
return `${diffHours}h ago`;
|
|
62715
|
+
if (diffDays < 7)
|
|
62716
|
+
return `${diffDays}d ago`;
|
|
62717
|
+
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
62718
|
+
}
|
|
62719
|
+
/**
|
|
62720
|
+
* InsightsPanelUI - Structured display of analytics insights.
|
|
62721
|
+
*
|
|
62722
|
+
* Renders a header with title and refresh button, filter chips
|
|
62723
|
+
* (All / Trends / Anomalies / Forecasts / Recommendations), and
|
|
62724
|
+
* insight cards with type icon, title, summary, confidence badge,
|
|
62725
|
+
* and relative timestamp. Includes loading skeleton and empty state.
|
|
62726
|
+
*
|
|
62727
|
+
* @example
|
|
62728
|
+
* ```tsx
|
|
62729
|
+
* <InsightsPanelUI
|
|
62730
|
+
* insights={insights}
|
|
62731
|
+
* isLoading={loading}
|
|
62732
|
+
* filter={activeFilter}
|
|
62733
|
+
* maxInsights={8}
|
|
62734
|
+
* onFilterChange={setFilter}
|
|
62735
|
+
* onRefresh={refreshInsights}
|
|
62736
|
+
* />
|
|
62737
|
+
* ```
|
|
62738
|
+
*/
|
|
62739
|
+
const InsightsPanelUI = React.forwardRef(({ insights, isLoading = false, filter = 'all', maxInsights, onFilterChange, onRefresh, className = '', }, ref) => {
|
|
62740
|
+
const filtered = filter === 'all'
|
|
62741
|
+
? insights
|
|
62742
|
+
: insights.filter((i) => i.type === filter);
|
|
62743
|
+
const displayed = maxInsights ? filtered.slice(0, maxInsights) : filtered;
|
|
62744
|
+
return (jsxRuntime.jsxs("div", { ref: ref, className: `bg-white rounded-lg border border-paper-200 ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-ink-900", children: "AI Insights" }), onRefresh && (jsxRuntime.jsx("button", { onClick: onRefresh, disabled: isLoading, className: "p-1.5 rounded-md text-ink-500 hover:text-ink-700 hover:bg-paper-100 disabled:opacity-40 transition-colors", "aria-label": "Refresh insights", children: jsxRuntime.jsx(lucideReact.RefreshCw, { className: `w-4 h-4 ${isLoading ? 'animate-spin' : ''}` }) }))] }), onFilterChange && (jsxRuntime.jsx("div", { className: "px-5 pt-3 pb-1 flex flex-wrap gap-2", children: FILTER_OPTIONS.map((opt) => (jsxRuntime.jsx("button", { onClick: () => onFilterChange(opt.key), className: `text-xs font-medium px-3 py-1.5 rounded-full transition-colors ${filter === opt.key
|
|
62745
|
+
? 'bg-primary-500 text-white'
|
|
62746
|
+
: 'bg-paper-100 text-ink-600 hover:bg-paper-200'}`, children: opt.label }, opt.key))) })), jsxRuntime.jsxs("div", { className: "p-5 space-y-3", children: [isLoading && displayed.length === 0 && (jsxRuntime.jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => (jsxRuntime.jsxs("div", { className: "animate-pulse rounded-lg border border-paper-200 p-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-2", children: [jsxRuntime.jsx("div", { className: "w-8 h-8 bg-paper-200 rounded-lg" }), jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsx("div", { className: "h-4 bg-paper-200 rounded w-2/3 mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-1/3" })] })] }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-full mb-1" }), jsxRuntime.jsx("div", { className: "h-3 bg-paper-100 rounded w-4/5" })] }, i))) })), !isLoading && displayed.length === 0 && (jsxRuntime.jsxs("div", { className: "text-center py-8", children: [jsxRuntime.jsx(lucideReact.BrainCircuit, { className: "w-10 h-10 text-ink-300 mx-auto mb-3" }), jsxRuntime.jsx("p", { className: "text-ink-500 text-sm", children: filter === 'all'
|
|
62747
|
+
? 'No insights available yet.'
|
|
62748
|
+
: `No ${filter} insights found.` })] })), displayed.map((insight) => (jsxRuntime.jsx("div", { className: "rounded-lg border border-paper-200 p-4 hover:shadow-sm transition-shadow", children: jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [jsxRuntime.jsx("div", { className: `flex-shrink-0 w-8 h-8 rounded-lg flex items-center justify-center ${getTypeBgColor(insight.type)}`, children: getTypeIcon(insight.type) }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [jsxRuntime.jsx("h4", { className: "text-sm font-medium text-ink-900 truncate", children: insight.title }), getConfidenceBadge(insight.confidence)] }), jsxRuntime.jsx("p", { className: "text-xs text-ink-600 leading-relaxed", children: insight.summary }), jsxRuntime.jsx("p", { className: "text-[10px] text-ink-400 mt-1.5", children: formatRelativeTime(insight.timestamp) })] })] }) }, insight.id)))] })] }));
|
|
62749
|
+
});
|
|
62750
|
+
InsightsPanelUI.displayName = 'InsightsPanelUI';
|
|
62751
|
+
|
|
62617
62752
|
exports.Accordion = Accordion;
|
|
62618
62753
|
exports.AchievementBadge = AchievementBadge;
|
|
62619
62754
|
exports.AchievementUnlock = AchievementUnlock;
|
|
@@ -62654,6 +62789,7 @@ exports.CardView = CardView;
|
|
|
62654
62789
|
exports.Carousel = Carousel;
|
|
62655
62790
|
exports.CaseQueueItem = CaseQueueItem;
|
|
62656
62791
|
exports.Celebration = Celebration;
|
|
62792
|
+
exports.ChatUI = ChatUI;
|
|
62657
62793
|
exports.Checkbox = Checkbox;
|
|
62658
62794
|
exports.CheckboxList = CheckboxList;
|
|
62659
62795
|
exports.Chip = Chip;
|
|
@@ -62721,6 +62857,7 @@ exports.HorizontalScroll = HorizontalScroll;
|
|
|
62721
62857
|
exports.HoverCard = HoverCard;
|
|
62722
62858
|
exports.InfiniteScroll = InfiniteScroll;
|
|
62723
62859
|
exports.Input = Input;
|
|
62860
|
+
exports.InsightsPanelUI = InsightsPanelUI;
|
|
62724
62861
|
exports.InviteCard = InviteCard;
|
|
62725
62862
|
exports.KanbanBoard = KanbanBoard;
|
|
62726
62863
|
exports.Layout = Layout;
|