@lindaui/blocks 0.4.2 → 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 +56 -0
- package/dist/ai-cost-card-f403ypsg.js +99 -0
- package/dist/ai-performance-card-cggm09nc.js +191 -0
- package/dist/analytics/ai-cost-card.d.ts +3 -0
- package/dist/analytics/ai-cost-card.d.ts.map +1 -0
- package/dist/analytics/ai-performance-card.d.ts +3 -0
- package/dist/analytics/ai-performance-card.d.ts.map +1 -0
- package/dist/analytics/analytics-card.d.ts +3 -0
- package/dist/analytics/analytics-card.d.ts.map +1 -0
- package/dist/analytics/analytics-skeleton.d.ts +5 -0
- package/dist/analytics/analytics-skeleton.d.ts.map +1 -0
- package/dist/analytics/entity-health-card.d.ts +3 -0
- package/dist/analytics/entity-health-card.d.ts.map +1 -0
- package/dist/analytics/status-distribution-chart.d.ts +3 -0
- package/dist/analytics/status-distribution-chart.d.ts.map +1 -0
- package/dist/analytics/time-range-picker.d.ts +3 -0
- package/dist/analytics/time-range-picker.d.ts.map +1 -0
- package/dist/analytics/top-entities-table.d.ts +3 -0
- package/dist/analytics/top-entities-table.d.ts.map +1 -0
- package/dist/analytics/types.d.ts +104 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics-card-bcmijpt6.js +38 -0
- package/dist/analytics-skeleton-imve37du.js +164 -0
- package/dist/analytics.d.ts +11 -0
- package/dist/analytics.d.ts.map +1 -0
- package/dist/analytics.js +8 -0
- package/dist/app-shell/drawer-focus.d.ts +8 -0
- package/dist/app-shell/drawer-focus.d.ts.map +1 -0
- package/dist/app-shell/footer.d.ts +39 -0
- package/dist/app-shell/footer.d.ts.map +1 -0
- package/dist/app-shell/logout-dialog.d.ts +6 -0
- package/dist/app-shell/logout-dialog.d.ts.map +1 -0
- package/dist/app-shell/navigation.d.ts +15 -0
- package/dist/app-shell/navigation.d.ts.map +1 -0
- package/dist/app-shell/types.d.ts +55 -0
- package/dist/app-shell/types.d.ts.map +1 -0
- package/dist/app-shell.d.ts +7 -0
- package/dist/app-shell.d.ts.map +1 -0
- package/dist/app-shell.js +254 -0
- package/dist/channel-settings.d.ts +24 -0
- package/dist/channel-settings.d.ts.map +1 -0
- package/dist/channel-settings.js +60 -0
- package/dist/chat-avatar-jdmeyf2o.js +30 -0
- package/dist/chat-layout-fwx3x26g.js +25 -0
- package/dist/chat.d.ts +22 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +66 -0
- package/dist/command-palette.d.ts +22 -0
- package/dist/command-palette.d.ts.map +1 -0
- package/dist/command-palette.js +141 -0
- package/dist/compat-chat/chat-avatar.d.ts +16 -0
- package/dist/compat-chat/chat-avatar.d.ts.map +1 -0
- package/dist/compat-chat/chat-header.d.ts +9 -0
- package/dist/compat-chat/chat-header.d.ts.map +1 -0
- package/dist/compat-chat/chat-layout.d.ts +10 -0
- package/dist/compat-chat/chat-layout.d.ts.map +1 -0
- package/dist/compat-chat/conversation-list-item.d.ts +10 -0
- package/dist/compat-chat/conversation-list-item.d.ts.map +1 -0
- package/dist/compat-chat/conversation-list.d.ts +24 -0
- package/dist/compat-chat/conversation-list.d.ts.map +1 -0
- package/dist/compat-chat/conversation-thread.d.ts +18 -0
- package/dist/compat-chat/conversation-thread.d.ts.map +1 -0
- package/dist/compat-chat/date-divider.d.ts +5 -0
- package/dist/compat-chat/date-divider.d.ts.map +1 -0
- package/dist/compat-chat/empty-chat-view.d.ts +6 -0
- package/dist/compat-chat/empty-chat-view.d.ts.map +1 -0
- package/dist/compat-chat/image-lightbox.d.ts +7 -0
- package/dist/compat-chat/image-lightbox.d.ts.map +1 -0
- package/dist/compat-chat/message-bubble.d.ts +6 -0
- package/dist/compat-chat/message-bubble.d.ts.map +1 -0
- package/dist/compat-chat/message-composer.d.ts +11 -0
- package/dist/compat-chat/message-composer.d.ts.map +1 -0
- package/dist/compat-chat/time-divider.d.ts +5 -0
- package/dist/compat-chat/time-divider.d.ts.map +1 -0
- package/dist/compat-chat/time-grouping.d.ts +5 -0
- package/dist/compat-chat/time-grouping.d.ts.map +1 -0
- package/dist/compat-chat/types.d.ts +35 -0
- package/dist/compat-chat/types.d.ts.map +1 -0
- package/dist/compat-chat/whatsapp-audio-player.d.ts +7 -0
- package/dist/compat-chat/whatsapp-audio-player.d.ts.map +1 -0
- package/dist/compat.d.ts +9 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +4 -0
- package/dist/connected-panel-lhwy25yk.js +132 -0
- package/dist/connection-panel/connected-panel.d.ts +26 -0
- package/dist/connection-panel/connected-panel.d.ts.map +1 -0
- package/dist/connection-panel/disconnected-panel.d.ts +12 -0
- package/dist/connection-panel/disconnected-panel.d.ts.map +1 -0
- package/dist/connection-panel/instructions.d.ts +5 -0
- package/dist/connection-panel/instructions.d.ts.map +1 -0
- package/dist/connection-panel/qr-panel.d.ts +14 -0
- package/dist/connection-panel/qr-panel.d.ts.map +1 -0
- package/dist/connection-panel/use-qr-refresh.d.ts +18 -0
- package/dist/connection-panel/use-qr-refresh.d.ts.map +1 -0
- package/dist/connection-panel.d.ts +39 -0
- package/dist/connection-panel.d.ts.map +1 -0
- package/dist/connection-panel.js +328 -0
- package/dist/conversation-list-ekq2dzca.js +133 -0
- package/dist/conversation-list-item-fy6t5af2.js +55 -0
- package/dist/conversation-thread-c60431oa.js +205 -0
- package/dist/entity-card.d.ts +17 -0
- package/dist/entity-card.d.ts.map +1 -0
- package/dist/entity-card.js +69 -0
- package/dist/entity-health-card-ggnmrtrq.js +192 -0
- package/dist/entity-switcher.d.ts +33 -0
- package/dist/entity-switcher.d.ts.map +1 -0
- package/dist/entity-switcher.js +137 -0
- package/dist/filter-bar.d.ts +41 -0
- package/dist/filter-bar.d.ts.map +1 -0
- package/dist/filter-bar.js +155 -0
- package/dist/footer-f7r5e42b.js +192 -0
- package/dist/image-lightbox-ci3arb6z.js +62 -0
- package/dist/kanban/drop-utils.d.ts +18 -0
- package/dist/kanban/drop-utils.d.ts.map +1 -0
- package/dist/kanban/navigation-buttons.d.ts +9 -0
- package/dist/kanban/navigation-buttons.d.ts.map +1 -0
- package/dist/kanban/scroll-indicators.d.ts +6 -0
- package/dist/kanban/scroll-indicators.d.ts.map +1 -0
- package/dist/kanban/use-keyboard-navigation.d.ts +4 -0
- package/dist/kanban/use-keyboard-navigation.d.ts.map +1 -0
- package/dist/kanban-board.d.ts +31 -0
- package/dist/kanban-board.d.ts.map +1 -0
- package/dist/kanban-board.js +128 -0
- package/dist/kanban-column.d.ts +13 -0
- package/dist/kanban-column.d.ts.map +1 -0
- package/dist/kanban-column.js +58 -0
- package/dist/legacy-kpi-card.d.ts +16 -0
- package/dist/legacy-kpi-card.d.ts.map +1 -0
- package/dist/legacy-kpi-card.js +4 -0
- package/dist/logout-dialog-bbv59tbi.js +93 -0
- package/dist/message-bubble-odjvhroq.js +110 -0
- package/dist/message-composer-m2n6soo7.js +59 -0
- package/dist/navigation-buttons-e77mshh0.js +65 -0
- package/dist/navigation-hotcrqoq.js +115 -0
- package/dist/save-bar.d.ts +15 -0
- package/dist/save-bar.d.ts.map +1 -0
- package/dist/save-bar.js +38 -0
- package/dist/scroll-indicators-gvxapogd.js +39 -0
- package/dist/settings-layout.d.ts +20 -0
- package/dist/settings-layout.d.ts.map +1 -0
- package/dist/settings-layout.js +56 -0
- package/dist/source-selector.d.ts +18 -0
- package/dist/source-selector.d.ts.map +1 -0
- package/dist/source-selector.js +59 -0
- package/dist/status-distribution-chart-oucedzv7.js +87 -0
- package/dist/status-filters.d.ts +12 -0
- package/dist/status-filters.d.ts.map +1 -0
- package/dist/status-filters.js +31 -0
- package/dist/stepper.d.ts +15 -0
- package/dist/stepper.d.ts.map +1 -0
- package/dist/stepper.js +42 -0
- package/dist/time-range-picker-mu38hul4.js +123 -0
- package/dist/top-entities-table-o7xzpq96.js +78 -0
- package/dist/use-keyboard-navigation-he1xmriz.js +52 -0
- package/dist/whatsapp-audio-player-nooty6jb.js +277 -0
- package/llms.txt +87 -4
- package/package.json +191 -46
- package/src/analytics/ai-cost-card.tsx +31 -0
- package/src/analytics/ai-performance-card.tsx +48 -0
- package/src/analytics/analytics-card.tsx +14 -0
- package/src/analytics/analytics-skeleton.tsx +15 -0
- package/src/analytics/entity-health-card.tsx +50 -0
- package/src/analytics/status-distribution-chart.tsx +20 -0
- package/src/analytics/time-range-picker.tsx +43 -0
- package/src/analytics/top-entities-table.tsx +24 -0
- package/src/analytics/types.ts +43 -0
- package/src/analytics.ts +10 -0
- package/src/app-shell/drawer-focus.ts +42 -0
- package/src/app-shell/footer.tsx +160 -0
- package/src/app-shell/logout-dialog.tsx +68 -0
- package/src/app-shell/navigation.tsx +147 -0
- package/src/app-shell/types.ts +57 -0
- package/src/app-shell.tsx +166 -0
- package/src/area-chart.tsx +85 -0
- package/src/audio-player.tsx +74 -0
- package/src/auth-layout.tsx +132 -0
- package/src/auth-provider.tsx +29 -0
- package/src/bar-chart.tsx +78 -0
- package/src/channel-settings.tsx +76 -0
- package/src/chart-card.tsx +45 -0
- package/src/chat-avatar.tsx +57 -0
- package/src/chat-date-divider.tsx +18 -0
- package/src/chat-header.tsx +24 -0
- package/src/chat-layout.tsx +41 -0
- package/src/chat-time-divider.tsx +20 -0
- package/src/chat-types.ts +32 -0
- package/src/chat.ts +21 -0
- package/src/command-palette.tsx +110 -0
- package/src/compat-chat/chat-avatar.tsx +23 -0
- package/src/compat-chat/chat-header.tsx +12 -0
- package/src/compat-chat/chat-layout.tsx +14 -0
- package/src/compat-chat/conversation-list-item.tsx +27 -0
- package/src/compat-chat/conversation-list.tsx +49 -0
- package/src/compat-chat/conversation-thread.tsx +92 -0
- package/src/compat-chat/date-divider.tsx +7 -0
- package/src/compat-chat/empty-chat-view.tsx +9 -0
- package/src/compat-chat/image-lightbox.tsx +22 -0
- package/src/compat-chat/message-bubble.tsx +28 -0
- package/src/compat-chat/message-composer.tsx +26 -0
- package/src/compat-chat/time-divider.tsx +5 -0
- package/src/compat-chat/time-grouping.ts +19 -0
- package/src/compat-chat/types.ts +31 -0
- package/src/compat-chat/whatsapp-audio-player.tsx +100 -0
- package/src/compat.ts +8 -0
- package/src/confirm-dialog.tsx +85 -0
- package/src/connection-panel/connected-panel.tsx +106 -0
- package/src/connection-panel/disconnected-panel.tsx +48 -0
- package/src/connection-panel/instructions.tsx +9 -0
- package/src/connection-panel/qr-panel.tsx +62 -0
- package/src/connection-panel/use-qr-refresh.ts +52 -0
- package/src/connection-panel.tsx +141 -0
- package/src/conversation-list-item.tsx +53 -0
- package/src/conversation-list.tsx +67 -0
- package/src/conversation-thread.tsx +64 -0
- package/src/detail-panel.tsx +123 -0
- package/src/document-panel.tsx +109 -0
- package/src/document-reader.tsx +29 -0
- package/src/empty-chat-view.tsx +25 -0
- package/src/entity-card.tsx +74 -0
- package/src/entity-health-card.tsx +53 -0
- package/src/entity-switcher.tsx +126 -0
- package/src/fetching-indicator.tsx +16 -0
- package/src/field-array-form.tsx +166 -0
- package/src/filter-bar.tsx +203 -0
- package/src/image-viewer.tsx +129 -0
- package/src/kanban/drop-utils.ts +31 -0
- package/src/kanban/navigation-buttons.tsx +80 -0
- package/src/kanban/scroll-indicators.tsx +47 -0
- package/src/kanban/use-keyboard-navigation.ts +43 -0
- package/src/kanban-board.tsx +160 -0
- package/src/kanban-column.tsx +62 -0
- package/src/legacy-kpi-card.tsx +38 -0
- package/src/line-chart.tsx +58 -0
- package/src/list-item.tsx +63 -0
- package/src/list-pane.tsx +143 -0
- package/src/login-form.tsx +128 -0
- package/src/message-bubble.tsx +70 -0
- package/src/message-composer.tsx +52 -0
- package/src/pie-chart.tsx +70 -0
- package/src/radar-chart.tsx +55 -0
- package/src/radial-chart.tsx +103 -0
- package/src/recording-overlay.tsx +159 -0
- package/src/save-bar.tsx +35 -0
- package/src/settings-layout.tsx +79 -0
- package/src/source-selector.tsx +71 -0
- package/src/split-workspace.tsx +74 -0
- package/src/stat-card.tsx +166 -0
- package/src/stats-grid.tsx +23 -0
- package/src/status-filters.tsx +28 -0
- package/src/stepper.tsx +47 -0
- package/src/table-pane.tsx +194 -0
- package/src/time-range-picker.tsx +89 -0
- package/src/workspace-back-button.tsx +32 -0
- package/dist/chat-types.test.d.ts +0 -2
- package/dist/chat-types.test.d.ts.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
export interface NavigationButtonsProps {
|
|
3
|
+
scrollRef: RefObject<HTMLElement | null>;
|
|
4
|
+
columnWidth?: number;
|
|
5
|
+
leftLabel?: string;
|
|
6
|
+
rightLabel?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function NavigationButtons({ scrollRef, columnWidth, leftLabel, rightLabel, }: NavigationButtonsProps): import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=navigation-buttons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-buttons.d.ts","sourceRoot":"","sources":["../../src/kanban/navigation-buttons.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,WAAiB,EACjB,SAAyB,EACzB,UAA2B,GAC5B,EAAE,sBAAsB,+BA4DxB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
export interface ScrollIndicatorsProps {
|
|
3
|
+
scrollRef: RefObject<HTMLElement | null>;
|
|
4
|
+
}
|
|
5
|
+
export declare function ScrollIndicators({ scrollRef }: ScrollIndicatorsProps): import("react").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=scroll-indicators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-indicators.d.ts","sourceRoot":"","sources":["../../src/kanban/scroll-indicators.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5D,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC1C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,EAAE,qBAAqB,+BAqCpE"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/** Preserve horizontal board navigation, without intercepting text editing. */
|
|
3
|
+
export declare function useKeyboardNavigation<T extends HTMLElement>(scrollRef: RefObject<T | null>, columnWidth?: number): void;
|
|
4
|
+
//# sourceMappingURL=use-keyboard-navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-keyboard-navigation.d.ts","sourceRoot":"","sources":["../../src/kanban/use-keyboard-navigation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElD,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,WAAW,EACzD,SAAS,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EAC9B,WAAW,SAAM,QAmClB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type UniqueIdentifier } from "@dnd-kit/core";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
export { resolveKanbanDrop } from "./kanban/drop-utils.js";
|
|
4
|
+
export { NavigationButtons, type NavigationButtonsProps } from "./kanban/navigation-buttons.js";
|
|
5
|
+
export { ScrollIndicators, type ScrollIndicatorsProps } from "./kanban/scroll-indicators.js";
|
|
6
|
+
export { useKeyboardNavigation } from "./kanban/use-keyboard-navigation.js";
|
|
7
|
+
export interface KanbanColumnDefinition<ColumnId extends UniqueIdentifier = string> {
|
|
8
|
+
id: ColumnId;
|
|
9
|
+
title: ReactNode;
|
|
10
|
+
colorClassName?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface KanbanCardState {
|
|
13
|
+
isDragging: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface KanbanBoardProps<Entity, ColumnId extends UniqueIdentifier = string> {
|
|
16
|
+
/** Entity and column IDs must be stable and unique across the whole board. */
|
|
17
|
+
entities: readonly Entity[];
|
|
18
|
+
columns: readonly KanbanColumnDefinition<ColumnId>[];
|
|
19
|
+
getEntityId: (entity: Entity) => UniqueIdentifier;
|
|
20
|
+
getColumnId: (entity: Entity) => ColumnId;
|
|
21
|
+
onColumnChange: (entityId: UniqueIdentifier, columnId: ColumnId, entity: Entity) => void;
|
|
22
|
+
renderCard: (entity: Entity, state: KanbanCardState) => ReactNode;
|
|
23
|
+
renderColumn?: (column: KanbanColumnDefinition<ColumnId>, entities: readonly Entity[]) => ReactNode;
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
emptyContent?: ReactNode;
|
|
26
|
+
ariaLabel?: string;
|
|
27
|
+
scrollLeftLabel?: string;
|
|
28
|
+
scrollRightLabel?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function KanbanBoard<Entity, ColumnId extends UniqueIdentifier = string>({ entities, columns, getEntityId, getColumnId, onColumnChange, renderCard, renderColumn, isLoading, emptyContent, ariaLabel, scrollLeftLabel, scrollRightLabel, }: KanbanBoardProps<Entity, ColumnId>): import("react").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=kanban-board.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kanban-board.d.ts","sourceRoot":"","sources":["../src/kanban-board.tsx"],"names":[],"mappings":"AAEA,OAAO,EAUL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gCAA6B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,+BAA4B,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAkC,CAAC;AAEzE,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS,gBAAgB,GAAG,MAAM;IAChF,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB,CAAC,MAAM,EAAE,QAAQ,SAAS,gBAAgB,GAAG,MAAM;IAClF,8EAA8E;IAC9E,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,SAAS,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACrD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAClD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC;IAC1C,cAAc,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzF,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,KAAK,SAAS,CAAC;IAClE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,KAAK,SAAS,CAAC;IACpG,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,SAAS,gBAAgB,GAAG,MAAM,EAAE,EAC9E,QAAQ,EACR,OAAO,EACP,WAAW,EACX,WAAW,EACX,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAiB,EACjB,YAAY,EACZ,SAA0B,EAC1B,eAAe,EACf,gBAAgB,GACjB,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,+BA6FpC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useSensors, useSensor, PointerSensor, TouchSensor, DndContext, closestCorners, DragOverlay } from '@dnd-kit/core';
|
|
4
|
+
import { Skeleton } from '@lindaui/ui/compound';
|
|
5
|
+
import { useState, useRef, Fragment } from 'react';
|
|
6
|
+
import { KanbanColumn } from './kanban-column.js';
|
|
7
|
+
import { N as NavigationButtons } from './navigation-buttons-e77mshh0.js';
|
|
8
|
+
import { S as ScrollIndicators } from './scroll-indicators-gvxapogd.js';
|
|
9
|
+
import { u as useKeyboardNavigation } from './use-keyboard-navigation-he1xmriz.js';
|
|
10
|
+
|
|
11
|
+
/** Resolve column and card targets without mutating the controlled collection. */ function resolveKanbanDrop({ activeId, overId, entities, columns, getEntityId, getColumnId }) {
|
|
12
|
+
if (overId === null) return null;
|
|
13
|
+
const entity = entities.find((item)=>getEntityId(item) === activeId);
|
|
14
|
+
if (entity === undefined) return null;
|
|
15
|
+
const targetEntity = entities.find((item)=>getEntityId(item) === overId);
|
|
16
|
+
const targetColumn = columns.find((column)=>column.id === overId);
|
|
17
|
+
const columnId = targetEntity !== undefined ? getColumnId(targetEntity) : targetColumn?.id;
|
|
18
|
+
if (columnId === undefined || columnId === getColumnId(entity)) return null;
|
|
19
|
+
if (!columns.some((column)=>column.id === columnId)) return null;
|
|
20
|
+
return {
|
|
21
|
+
entity,
|
|
22
|
+
entityId: activeId,
|
|
23
|
+
columnId
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function KanbanBoard({ entities, columns, getEntityId, getColumnId, onColumnChange, renderCard, renderColumn, isLoading = false, emptyContent, ariaLabel = "Kanban board", scrollLeftLabel, scrollRightLabel }) {
|
|
28
|
+
const [activeId, setActiveId] = useState(null);
|
|
29
|
+
const scrollRef = useRef(null);
|
|
30
|
+
useKeyboardNavigation(scrollRef);
|
|
31
|
+
const sensors = useSensors(useSensor(PointerSensor, {
|
|
32
|
+
activationConstraint: {
|
|
33
|
+
distance: 8
|
|
34
|
+
}
|
|
35
|
+
}), useSensor(TouchSensor, {
|
|
36
|
+
activationConstraint: {
|
|
37
|
+
delay: 200,
|
|
38
|
+
tolerance: 5
|
|
39
|
+
}
|
|
40
|
+
}));
|
|
41
|
+
const handleDragStart = (event)=>setActiveId(event.active.id);
|
|
42
|
+
const handleDragEnd = (event)=>{
|
|
43
|
+
setActiveId(null);
|
|
44
|
+
const drop = resolveKanbanDrop({
|
|
45
|
+
activeId: event.active.id,
|
|
46
|
+
overId: event.over?.id ?? null,
|
|
47
|
+
entities,
|
|
48
|
+
columns,
|
|
49
|
+
getEntityId,
|
|
50
|
+
getColumnId
|
|
51
|
+
});
|
|
52
|
+
if (drop) onColumnChange(drop.entityId, drop.columnId, drop.entity);
|
|
53
|
+
};
|
|
54
|
+
const activeEntity = activeId !== null ? entities.find((entity)=>getEntityId(entity) === activeId) : null;
|
|
55
|
+
if (isLoading) {
|
|
56
|
+
return /*#__PURE__*/ jsx("div", {
|
|
57
|
+
className: "flex h-full gap-4 overflow-x-auto p-4 lg:p-6",
|
|
58
|
+
children: columns.map((column)=>/*#__PURE__*/ jsxs("div", {
|
|
59
|
+
className: "flex w-80 flex-shrink-0 flex-col gap-3",
|
|
60
|
+
children: [
|
|
61
|
+
/*#__PURE__*/ jsx(Skeleton, {
|
|
62
|
+
className: "h-8 w-24 rounded-lg"
|
|
63
|
+
}),
|
|
64
|
+
/*#__PURE__*/ jsx("div", {
|
|
65
|
+
className: "min-h-[500px] space-y-3 rounded-xl bg-surface-secondary/50 p-2",
|
|
66
|
+
children: Array.from({
|
|
67
|
+
length: 3
|
|
68
|
+
}).map((_, index)=>/*#__PURE__*/ jsx(Skeleton, {
|
|
69
|
+
className: "h-32 w-full rounded-xl"
|
|
70
|
+
}, index))
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
}, column.id))
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return /*#__PURE__*/ jsxs(DndContext, {
|
|
77
|
+
collisionDetection: closestCorners,
|
|
78
|
+
onDragEnd: handleDragEnd,
|
|
79
|
+
onDragStart: handleDragStart,
|
|
80
|
+
sensors: sensors,
|
|
81
|
+
children: [
|
|
82
|
+
/*#__PURE__*/ jsxs("div", {
|
|
83
|
+
className: "relative h-full w-full overflow-hidden",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ jsx(ScrollIndicators, {
|
|
86
|
+
scrollRef: scrollRef
|
|
87
|
+
}),
|
|
88
|
+
/*#__PURE__*/ jsx(NavigationButtons, {
|
|
89
|
+
scrollRef: scrollRef,
|
|
90
|
+
leftLabel: scrollLeftLabel,
|
|
91
|
+
rightLabel: scrollRightLabel
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ jsx("section", {
|
|
94
|
+
"aria-label": ariaLabel,
|
|
95
|
+
className: "flex h-full gap-4 overflow-x-auto overflow-y-visible p-4 lg:p-6",
|
|
96
|
+
ref: scrollRef,
|
|
97
|
+
children: columns.map((column)=>{
|
|
98
|
+
const items = entities.filter((entity)=>getColumnId(entity) === column.id);
|
|
99
|
+
return /*#__PURE__*/ jsx(Fragment, {
|
|
100
|
+
children: renderColumn ? renderColumn(column, items) : /*#__PURE__*/ jsx(KanbanColumn, {
|
|
101
|
+
id: column.id,
|
|
102
|
+
title: column.title,
|
|
103
|
+
entities: items,
|
|
104
|
+
getEntityId: getEntityId,
|
|
105
|
+
renderCard: (entity)=>renderCard(entity, {
|
|
106
|
+
isDragging: false
|
|
107
|
+
}),
|
|
108
|
+
colorClassName: column.colorClassName,
|
|
109
|
+
emptyContent: emptyContent
|
|
110
|
+
})
|
|
111
|
+
}, column.id);
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
]
|
|
115
|
+
}),
|
|
116
|
+
/*#__PURE__*/ jsx(DragOverlay, {
|
|
117
|
+
children: activeEntity !== null && activeEntity !== undefined ? /*#__PURE__*/ jsx("div", {
|
|
118
|
+
className: "rotate-3 opacity-80",
|
|
119
|
+
children: renderCard(activeEntity, {
|
|
120
|
+
isDragging: true
|
|
121
|
+
})
|
|
122
|
+
}) : null
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { KanbanBoard, NavigationButtons, ScrollIndicators, resolveKanbanDrop, useKeyboardNavigation };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type UniqueIdentifier } from "@dnd-kit/core";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
export interface KanbanColumnProps<Entity> {
|
|
4
|
+
id: UniqueIdentifier;
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
entities: readonly Entity[];
|
|
7
|
+
getEntityId: (entity: Entity) => UniqueIdentifier;
|
|
8
|
+
renderCard: (entity: Entity) => ReactNode;
|
|
9
|
+
colorClassName?: string;
|
|
10
|
+
emptyContent?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare function KanbanColumn<Entity>({ id, title, entities, getEntityId, renderCard, colorClassName, emptyContent, }: KanbanColumnProps<Entity>): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=kanban-column.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kanban-column.d.ts","sourceRoot":"","sources":["../src/kanban-column.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGpE,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjD,MAAM,WAAW,iBAAiB,CAAC,MAAM;IACvC,EAAE,EAAE,gBAAgB,CAAC;IACrB,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,gBAAgB,CAAC;IAClD,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,EACnC,EAAE,EACF,KAAK,EACL,QAAQ,EACR,WAAW,EACX,UAAU,EACV,cAA+B,EAC/B,YAAyB,GAC1B,EAAE,iBAAiB,CAAC,MAAM,CAAC,+BAoC3B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useDroppable } from '@dnd-kit/core';
|
|
4
|
+
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
5
|
+
import { cn } from '@lindaui/ui/cn';
|
|
6
|
+
import { Fragment } from 'react';
|
|
7
|
+
|
|
8
|
+
function KanbanColumn({ id, title, entities, getEntityId, renderCard, colorClassName = "bg-accent/60", emptyContent = "No items" }) {
|
|
9
|
+
const { setNodeRef, isOver } = useDroppable({
|
|
10
|
+
id
|
|
11
|
+
});
|
|
12
|
+
return /*#__PURE__*/ jsx("div", {
|
|
13
|
+
className: "flex h-full w-80 flex-shrink-0 flex-col",
|
|
14
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
15
|
+
className: "flex h-full flex-col overflow-hidden rounded-2xl bg-surface/50",
|
|
16
|
+
children: [
|
|
17
|
+
/*#__PURE__*/ jsx("div", {
|
|
18
|
+
className: cn("h-2.5", colorClassName)
|
|
19
|
+
}),
|
|
20
|
+
/*#__PURE__*/ jsxs("div", {
|
|
21
|
+
className: "flex items-center justify-between px-4 py-3",
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ jsx("h3", {
|
|
24
|
+
className: "font-semibold text-foreground",
|
|
25
|
+
children: title
|
|
26
|
+
}),
|
|
27
|
+
/*#__PURE__*/ jsx("span", {
|
|
28
|
+
className: "rounded-full bg-surface-secondary px-2 py-1 font-mono text-muted text-xs",
|
|
29
|
+
children: entities.length
|
|
30
|
+
})
|
|
31
|
+
]
|
|
32
|
+
}),
|
|
33
|
+
/*#__PURE__*/ jsxs("div", {
|
|
34
|
+
className: cn("min-h-[500px] flex-1 overflow-y-auto p-2 transition-colors", isOver ? "bg-accent/10" : ""),
|
|
35
|
+
ref: setNodeRef,
|
|
36
|
+
children: [
|
|
37
|
+
/*#__PURE__*/ jsx(SortableContext, {
|
|
38
|
+
items: entities.map(getEntityId),
|
|
39
|
+
strategy: verticalListSortingStrategy,
|
|
40
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
41
|
+
className: "space-y-3",
|
|
42
|
+
children: entities.map((entity)=>/*#__PURE__*/ jsx(Fragment, {
|
|
43
|
+
children: renderCard(entity)
|
|
44
|
+
}, getEntityId(entity)))
|
|
45
|
+
})
|
|
46
|
+
}),
|
|
47
|
+
entities.length === 0 && /*#__PURE__*/ jsx("div", {
|
|
48
|
+
className: "flex h-32 items-center justify-center text-muted text-sm",
|
|
49
|
+
children: emptyContent
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { KanbanColumn };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LucideIcon } from "lucide-react";
|
|
2
|
+
export type KPICardColor = "default" | "success" | "primary" | "warning";
|
|
3
|
+
export interface KPICardProps {
|
|
4
|
+
color?: KPICardColor;
|
|
5
|
+
icon: LucideIcon;
|
|
6
|
+
isLoading?: boolean;
|
|
7
|
+
title: string;
|
|
8
|
+
trend?: {
|
|
9
|
+
value: number;
|
|
10
|
+
isPositive: boolean;
|
|
11
|
+
};
|
|
12
|
+
value: string | number;
|
|
13
|
+
}
|
|
14
|
+
/** Exact legacy KPI anatomy; StatCard and its featured variant remain unchanged. */
|
|
15
|
+
export declare function KPICard({ title, value, icon: Icon, trend, color, isLoading }: KPICardProps): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=legacy-kpi-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-kpi-card.d.ts","sourceRoot":"","sources":["../src/legacy-kpi-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AACzE,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB;AAOD,oFAAoF;AACpF,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAiB,EAAE,SAAiB,EAAE,EAAE,YAAY,+BAe9G"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { Modal, Button, Spinner } from '@lindaui/ui/compound';
|
|
4
|
+
import { useState, useRef } from 'react';
|
|
5
|
+
|
|
6
|
+
function useLogoutDialog(onSignOut, labels) {
|
|
7
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
+
const [isPending, setIsPending] = useState(false);
|
|
9
|
+
const [error, setError] = useState(null);
|
|
10
|
+
const pending = useRef(false);
|
|
11
|
+
const onOpenChange = (open)=>{
|
|
12
|
+
if (pending.current) return;
|
|
13
|
+
setError(null);
|
|
14
|
+
setIsOpen(open);
|
|
15
|
+
};
|
|
16
|
+
const confirm = async ()=>{
|
|
17
|
+
if (pending.current) return;
|
|
18
|
+
pending.current = true;
|
|
19
|
+
setIsPending(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
await onSignOut();
|
|
23
|
+
setIsOpen(false);
|
|
24
|
+
} catch {
|
|
25
|
+
setError(labels.logoutError);
|
|
26
|
+
} finally{
|
|
27
|
+
pending.current = false;
|
|
28
|
+
setIsPending(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
open: ()=>onOpenChange(true),
|
|
33
|
+
dialog: /*#__PURE__*/ jsx(Modal.Backdrop, {
|
|
34
|
+
isDismissable: !isPending,
|
|
35
|
+
isKeyboardDismissDisabled: isPending,
|
|
36
|
+
isOpen: isOpen,
|
|
37
|
+
onOpenChange: onOpenChange,
|
|
38
|
+
children: /*#__PURE__*/ jsx(Modal.Container, {
|
|
39
|
+
children: /*#__PURE__*/ jsxs(Modal.Dialog, {
|
|
40
|
+
className: "sm:max-w-md",
|
|
41
|
+
role: "alertdialog",
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ jsx(Modal.Header, {
|
|
44
|
+
children: /*#__PURE__*/ jsx(Modal.Heading, {
|
|
45
|
+
children: labels.logoutTitle
|
|
46
|
+
})
|
|
47
|
+
}),
|
|
48
|
+
/*#__PURE__*/ jsxs(Modal.Body, {
|
|
49
|
+
children: [
|
|
50
|
+
/*#__PURE__*/ jsx("p", {
|
|
51
|
+
className: "text-muted text-sm leading-relaxed",
|
|
52
|
+
children: labels.logoutDescription
|
|
53
|
+
}),
|
|
54
|
+
error ? /*#__PURE__*/ jsx("p", {
|
|
55
|
+
className: "mt-3 text-danger text-sm",
|
|
56
|
+
role: "alert",
|
|
57
|
+
children: error
|
|
58
|
+
}) : null
|
|
59
|
+
]
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ jsxs(Modal.Footer, {
|
|
62
|
+
children: [
|
|
63
|
+
/*#__PURE__*/ jsx(Button, {
|
|
64
|
+
autoFocus: true,
|
|
65
|
+
isDisabled: isPending,
|
|
66
|
+
onPress: ()=>onOpenChange(false),
|
|
67
|
+
variant: "tertiary",
|
|
68
|
+
children: labels.logoutCancel
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ jsx(Button, {
|
|
71
|
+
isPending: isPending,
|
|
72
|
+
onPress: confirm,
|
|
73
|
+
variant: "danger",
|
|
74
|
+
children: ({ isPending: buttonPending })=>/*#__PURE__*/ jsxs(Fragment, {
|
|
75
|
+
children: [
|
|
76
|
+
buttonPending ? /*#__PURE__*/ jsx(Spinner, {
|
|
77
|
+
color: "current",
|
|
78
|
+
size: "sm"
|
|
79
|
+
}) : null,
|
|
80
|
+
buttonPending ? labels.logoutPending : labels.logoutConfirm
|
|
81
|
+
]
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { useLogoutDialog as u };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { cn } from '@lindaui/ui/cn';
|
|
6
|
+
import { I as ImageLightbox } from './image-lightbox-ci3arb6z.js';
|
|
7
|
+
import { W as WhatsAppAudioPlayer } from './whatsapp-audio-player-nooty6jb.js';
|
|
8
|
+
|
|
9
|
+
function formatTime(date) {
|
|
10
|
+
return dayjs(date).format("HH:mm");
|
|
11
|
+
}
|
|
12
|
+
function MessageBubble({ message }) {
|
|
13
|
+
const isBot = message.side === "right";
|
|
14
|
+
const hasAudio = message.media?.kind === "audio";
|
|
15
|
+
if (message.side === "center") return /*#__PURE__*/ jsx(motion.div, {
|
|
16
|
+
animate: {
|
|
17
|
+
opacity: 1
|
|
18
|
+
},
|
|
19
|
+
className: "my-2 flex justify-center",
|
|
20
|
+
initial: {
|
|
21
|
+
opacity: 0
|
|
22
|
+
},
|
|
23
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
24
|
+
className: "rounded-full bg-surface-secondary px-3 py-1 text-muted text-xs",
|
|
25
|
+
children: message.text
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
return /*#__PURE__*/ jsx(motion.div, {
|
|
29
|
+
animate: {
|
|
30
|
+
opacity: 1,
|
|
31
|
+
y: 0
|
|
32
|
+
},
|
|
33
|
+
className: cn("flex w-full", isBot ? "justify-end" : "justify-start"),
|
|
34
|
+
initial: {
|
|
35
|
+
opacity: 0,
|
|
36
|
+
y: 10
|
|
37
|
+
},
|
|
38
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
39
|
+
className: cn("relative p-3 text-sm shadow-sm", hasAudio ? "w-[90%] max-w-[330px]" : "max-w-[85%] sm:max-w-[70%]", "rounded-2xl transition-all duration-200", isBot ? "rounded-tr-none bg-[#d9fdd3] text-[#111b21] dark:bg-[#005c4b] dark:text-white" : "rounded-tl-none bg-white text-[#111b21] dark:bg-[#202c33] dark:text-white"),
|
|
40
|
+
children: [
|
|
41
|
+
/*#__PURE__*/ jsx("div", {
|
|
42
|
+
className: cn("absolute top-0 h-0 w-0 border-solid", isBot ? "-right-[12px] border-t-[#d9fdd3] border-t-[10px] border-r-[12px] border-r-transparent dark:border-t-[#005c4b]" : "-left-[12px] border-t-[10px] border-t-white border-l-[12px] border-l-transparent dark:border-t-[#202c33]")
|
|
43
|
+
}),
|
|
44
|
+
message.media?.kind === "image" && /*#__PURE__*/ jsx("div", {
|
|
45
|
+
className: "mb-2 overflow-hidden rounded-lg",
|
|
46
|
+
children: /*#__PURE__*/ jsx(ImageLightbox, {
|
|
47
|
+
alt: "Media compartida",
|
|
48
|
+
src: message.media.url
|
|
49
|
+
})
|
|
50
|
+
}),
|
|
51
|
+
message.media?.kind === "audio" && /*#__PURE__*/ jsx("div", {
|
|
52
|
+
className: "mb-2",
|
|
53
|
+
children: /*#__PURE__*/ jsx(WhatsAppAudioPlayer, {
|
|
54
|
+
isBot: isBot,
|
|
55
|
+
src: message.media.url
|
|
56
|
+
})
|
|
57
|
+
}),
|
|
58
|
+
message.media?.kind === "pdf" && /*#__PURE__*/ jsx("div", {
|
|
59
|
+
className: "mb-2",
|
|
60
|
+
children: /*#__PURE__*/ jsxs("a", {
|
|
61
|
+
className: "flex items-center gap-1.5 rounded-lg border border-border bg-surface-secondary px-3 py-2 text-sm text-foreground transition-colors hover:bg-surface-secondary dark:border-border dark:bg-default dark:text-muted dark:hover:bg-default",
|
|
62
|
+
download: true,
|
|
63
|
+
href: message.media.url,
|
|
64
|
+
rel: "noopener noreferrer",
|
|
65
|
+
target: "_blank",
|
|
66
|
+
children: [
|
|
67
|
+
/*#__PURE__*/ jsx("span", {
|
|
68
|
+
children: "PDF"
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ jsx("span", {
|
|
71
|
+
className: "max-w-[180px] truncate",
|
|
72
|
+
children: message.media.label ?? "Documento adjunto"
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
}),
|
|
77
|
+
/*#__PURE__*/ jsxs("div", {
|
|
78
|
+
className: "relative",
|
|
79
|
+
children: [
|
|
80
|
+
/*#__PURE__*/ jsxs("p", {
|
|
81
|
+
className: "whitespace-pre-wrap break-words",
|
|
82
|
+
children: [
|
|
83
|
+
message.text,
|
|
84
|
+
/*#__PURE__*/ jsxs("span", {
|
|
85
|
+
className: "invisible text-[10px]",
|
|
86
|
+
children: [
|
|
87
|
+
" ",
|
|
88
|
+
formatTime(message.timestamp),
|
|
89
|
+
message.authorTag ? ` ${message.authorTag}` : ""
|
|
90
|
+
]
|
|
91
|
+
})
|
|
92
|
+
]
|
|
93
|
+
}),
|
|
94
|
+
/*#__PURE__*/ jsxs("span", {
|
|
95
|
+
className: "absolute right-0 bottom-0 flex items-center gap-1 text-[#52616b] text-[10px] dark:text-[#d1dedb]",
|
|
96
|
+
children: [
|
|
97
|
+
formatTime(message.timestamp),
|
|
98
|
+
message.authorTag && /*#__PURE__*/ jsx("span", {
|
|
99
|
+
children: message.authorTag
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
})
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
]
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { MessageBubble as M };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { TextArea, Button, Spinner } from '@lindaui/ui/compound';
|
|
4
|
+
import { Send, Mic } from 'lucide-react';
|
|
5
|
+
import { useCallback } from 'react';
|
|
6
|
+
|
|
7
|
+
/** Controlled glass composer; Enter sends and Shift+Enter retains a newline. */ function MessageComposer({ value, onValueChange, onSend, isSending = false, placeholder, disabled = false }) {
|
|
8
|
+
const hasText = value.trim().length > 0;
|
|
9
|
+
const handleChange = useCallback((e)=>onValueChange(e.target.value), [
|
|
10
|
+
onValueChange
|
|
11
|
+
]);
|
|
12
|
+
const handleKeyDown = useCallback((e)=>{
|
|
13
|
+
if (e.key === "Enter" && !e.shiftKey && !isSending) {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
if (hasText) onSend();
|
|
16
|
+
}
|
|
17
|
+
}, [
|
|
18
|
+
hasText,
|
|
19
|
+
isSending,
|
|
20
|
+
onSend
|
|
21
|
+
]);
|
|
22
|
+
return /*#__PURE__*/ jsx("div", {
|
|
23
|
+
className: "absolute inset-x-0 bottom-0 flex justify-center px-4 py-3",
|
|
24
|
+
children: /*#__PURE__*/ jsxs("div", {
|
|
25
|
+
className: "flex w-full items-end gap-2 rounded-3xl border border-white/30 bg-white/60 px-4 py-2 shadow-2xl backdrop-blur-2xl backdrop-saturate-200 transition-all lg:w-[70%] dark:border-white/15 dark:bg-slate-800/40",
|
|
26
|
+
children: [
|
|
27
|
+
/*#__PURE__*/ jsx(TextArea, {
|
|
28
|
+
"aria-label": placeholder,
|
|
29
|
+
className: "field-sizing-content max-h-30 min-h-0 flex-1 resize-none overflow-y-auto border-none bg-transparent py-1 text-foreground shadow-none dark:text-white",
|
|
30
|
+
disabled: disabled || isSending,
|
|
31
|
+
onChange: handleChange,
|
|
32
|
+
onKeyDown: handleKeyDown,
|
|
33
|
+
placeholder: placeholder,
|
|
34
|
+
rows: 1,
|
|
35
|
+
value: value
|
|
36
|
+
}),
|
|
37
|
+
/*#__PURE__*/ jsx(Button, {
|
|
38
|
+
className: "rounded-full bg-[#00a884] text-white",
|
|
39
|
+
isDisabled: disabled || isSending,
|
|
40
|
+
isIconOnly: true,
|
|
41
|
+
isPending: isSending,
|
|
42
|
+
onPress: hasText ? onSend : undefined,
|
|
43
|
+
size: "sm",
|
|
44
|
+
variant: "primary",
|
|
45
|
+
children: ({ isPending })=>isPending ? /*#__PURE__*/ jsx(Spinner, {
|
|
46
|
+
color: "current",
|
|
47
|
+
size: "sm"
|
|
48
|
+
}) : hasText ? /*#__PURE__*/ jsx(Send, {
|
|
49
|
+
className: "h-4 w-4"
|
|
50
|
+
}) : /*#__PURE__*/ jsx(Mic, {
|
|
51
|
+
className: "h-4 w-4"
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { MessageComposer as M };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { Button } from '@lindaui/ui/compound';
|
|
4
|
+
import { cn } from '@lindaui/ui/cn';
|
|
5
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
6
|
+
import { useState, useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
function NavigationButtons({ scrollRef, columnWidth = 320, leftLabel = "Scroll left", rightLabel = "Scroll right" }) {
|
|
9
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
10
|
+
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
11
|
+
useEffect(()=>{
|
|
12
|
+
const element = scrollRef.current;
|
|
13
|
+
if (!element) return;
|
|
14
|
+
const checkScroll = ()=>{
|
|
15
|
+
const { scrollLeft, scrollWidth, clientWidth } = element;
|
|
16
|
+
setCanScrollLeft(scrollLeft > 0);
|
|
17
|
+
setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 1);
|
|
18
|
+
};
|
|
19
|
+
checkScroll();
|
|
20
|
+
element.addEventListener("scroll", checkScroll);
|
|
21
|
+
window.addEventListener("resize", checkScroll);
|
|
22
|
+
return ()=>{
|
|
23
|
+
element.removeEventListener("scroll", checkScroll);
|
|
24
|
+
window.removeEventListener("resize", checkScroll);
|
|
25
|
+
};
|
|
26
|
+
}, [
|
|
27
|
+
scrollRef
|
|
28
|
+
]);
|
|
29
|
+
const scroll = (direction)=>{
|
|
30
|
+
const element = scrollRef.current;
|
|
31
|
+
if (!element) return;
|
|
32
|
+
element.scrollTo({
|
|
33
|
+
behavior: "smooth",
|
|
34
|
+
left: element.scrollLeft + (direction === "left" ? -columnWidth : columnWidth)
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
38
|
+
children: [
|
|
39
|
+
/*#__PURE__*/ jsx(Button, {
|
|
40
|
+
"aria-label": leftLabel,
|
|
41
|
+
className: cn("absolute top-1/2 left-4 z-20 -translate-y-1/2 rounded-full shadow-xl transition-opacity", canScrollLeft ? "opacity-100" : "pointer-events-none opacity-0"),
|
|
42
|
+
isIconOnly: true,
|
|
43
|
+
onPress: ()=>scroll("left"),
|
|
44
|
+
size: "md",
|
|
45
|
+
variant: "primary",
|
|
46
|
+
children: /*#__PURE__*/ jsx(ChevronLeft, {
|
|
47
|
+
className: "h-6 w-6"
|
|
48
|
+
})
|
|
49
|
+
}),
|
|
50
|
+
/*#__PURE__*/ jsx(Button, {
|
|
51
|
+
"aria-label": rightLabel,
|
|
52
|
+
className: cn("absolute top-1/2 right-4 z-20 -translate-y-1/2 rounded-full shadow-xl transition-opacity", canScrollRight ? "opacity-100" : "pointer-events-none opacity-0"),
|
|
53
|
+
isIconOnly: true,
|
|
54
|
+
onPress: ()=>scroll("right"),
|
|
55
|
+
size: "md",
|
|
56
|
+
variant: "primary",
|
|
57
|
+
children: /*#__PURE__*/ jsx(ChevronRight, {
|
|
58
|
+
className: "h-6 w-6"
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { NavigationButtons as N };
|