@softwareone/spi-sv5-library 1.10.2 → 1.10.3

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.
@@ -8,14 +8,49 @@
8
8
  interface ButtonProps extends HTMLButtonAttributes {
9
9
  variant?: Variant;
10
10
  variantColor?: VariantColor;
11
+ loading?: boolean;
11
12
  children: Snippet;
12
13
  }
13
14
 
14
- let { variant = 'primary', variantColor = 'primary', children, ...props }: ButtonProps = $props();
15
+ let {
16
+ variant = 'primary',
17
+ variantColor = 'primary',
18
+ loading = false,
19
+ children,
20
+ ...props
21
+ }: ButtonProps = $props();
15
22
  </script>
16
23
 
17
- <button class="btn btn-{variant}-{variantColor}" {...props}>
18
- {@render children()}
24
+ <button
25
+ class={['btn', `btn-${variant}-${variantColor}`, loading && 'loading']}
26
+ disabled={loading || props.disabled}
27
+ {...props}
28
+ >
29
+ {#if loading}
30
+ <span class="spinner-wrapper">
31
+ <svg
32
+ class="spinner"
33
+ width="16"
34
+ height="16"
35
+ viewBox="0 0 16 16"
36
+ fill="none"
37
+ xmlns="http://www.w3.org/2000/svg"
38
+ >
39
+ <path
40
+ d="M16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8ZM2.50919 8C2.50919 11.0325 4.96752 13.4908 8 13.4908C11.0325 13.4908 13.4908 11.0325 13.4908 8C13.4908 4.96752 11.0325 2.50919 8 2.50919C4.96752 2.50919 2.50919 4.96752 2.50919 8Z"
41
+ fill="currentColor"
42
+ opacity="0.3"
43
+ />
44
+ <path
45
+ d="M8 1.2546C8 0.561698 8.56514 -0.0100693 9.24952 0.0981505C10.9084 0.360457 12.4543 1.14062 13.6569 2.34315C15.1571 3.84344 16 5.87827 16 8C16 10.1217 15.1571 12.1566 13.6569 13.6569C12.4543 14.8594 10.9084 15.6396 9.24952 15.9018C8.56514 16.0101 8 15.4383 8 14.7454C8 14.0525 8.56889 13.5051 9.24375 13.3481C10.235 13.1176 11.1513 12.6138 11.8826 11.8826C12.9123 10.8529 13.4908 9.45641 13.4908 8C13.4908 6.54359 12.9123 5.14709 11.8826 4.11742C11.1513 3.38615 10.235 2.88245 9.24375 2.65189C8.56889 2.49492 8 1.9475 8 1.2546Z"
46
+ fill="currentColor"
47
+ />
48
+ </svg>
49
+ </span>
50
+ {/if}
51
+ <span class="content" class:hidden={loading}>
52
+ {@render children()}
53
+ </span>
19
54
  </button>
20
55
 
21
56
  <style>
@@ -27,6 +62,56 @@
27
62
  font-style: normal;
28
63
  font-weight: 400;
29
64
  line-height: 20px;
65
+ display: inline-flex;
66
+ position: relative;
67
+ transition: all 0.2s ease-in-out;
68
+ }
69
+
70
+ .content.hidden {
71
+ opacity: 0;
72
+ }
73
+
74
+ .spinner-wrapper {
75
+ position: absolute;
76
+ display: inline-flex;
77
+ align-items: center;
78
+ left: 50%;
79
+ top: 50%;
80
+ transform: translate(-50%, -50%);
81
+ }
82
+
83
+ .spinner {
84
+ animation: spin 0.8s linear infinite;
85
+ }
86
+
87
+ .btn-primary-primary .spinner,
88
+ .btn-primary-danger .spinner {
89
+ color: #fff;
90
+ }
91
+
92
+ .btn-secondary-primary .spinner,
93
+ .btn-outline-primary .spinner,
94
+ .btn-outline-none-primary .spinner {
95
+ color: #472aff;
96
+ }
97
+
98
+ .btn-secondary-danger .spinner,
99
+ .btn-outline-danger .spinner,
100
+ .btn-outline-none-danger .spinner {
101
+ color: #dc182c;
102
+ }
103
+
104
+ .btn.loading {
105
+ cursor: wait;
106
+ }
107
+
108
+ @keyframes spin {
109
+ from {
110
+ transform: rotate(0deg);
111
+ }
112
+ to {
113
+ transform: rotate(360deg);
114
+ }
30
115
  }
31
116
 
32
117
  .btn:hover:not(:disabled),
@@ -40,7 +125,7 @@
40
125
  outline: none;
41
126
  }
42
127
 
43
- .btn:disabled {
128
+ .btn:disabled:not(.loading) {
44
129
  background: #e0e5e8;
45
130
  border: none;
46
131
  color: #6b7180;
@@ -132,8 +217,8 @@
132
217
  background: #fce8ea;
133
218
  }
134
219
 
135
- .btn-outline-none-primary:disabled,
136
- .btn-outline-none-danger:disabled {
220
+ .btn-outline-none-primary:disabled:not(.loading),
221
+ .btn-outline-none-danger:disabled:not(.loading) {
137
222
  background: transparent;
138
223
  color: #6b7180;
139
224
  }
@@ -5,6 +5,7 @@ type VariantColor = 'primary' | 'danger';
5
5
  interface ButtonProps extends HTMLButtonAttributes {
6
6
  variant?: Variant;
7
7
  variantColor?: VariantColor;
8
+ loading?: boolean;
8
9
  children: Snippet;
9
10
  }
10
11
  declare const Button: import("svelte").Component<ButtonProps, {}, "">;
@@ -164,7 +164,7 @@
164
164
 
165
165
  .table-header-search {
166
166
  display: flex;
167
- width: 144px;
167
+ width: 100%;
168
168
  margin: var(--spacing-xs) 0;
169
169
  font-weight: var(--font-normal);
170
170
  }
@@ -1,4 +1,4 @@
1
1
  import type { Table } from './adapter/index.js';
2
2
  import { type ExcelSetting } from './excel-setting.js';
3
- declare const exportExcel: <T>(table: Table<T>, excelSetting: ExcelSetting) => Promise<void>;
3
+ export declare const exportExcel: <T>(table: Table<T>, excelSetting: ExcelSetting) => Promise<void>;
4
4
  export default exportExcel;
@@ -2,7 +2,7 @@
2
2
  import ExcelJS from 'exceljs';
3
3
  import saveAs from 'file-saver';
4
4
  import { ColumnFormat } from './excel-setting.js';
5
- const exportExcel = async (table, excelSetting) => {
5
+ export const exportExcel = async (table, excelSetting) => {
6
6
  const workbook = new ExcelJS.Workbook();
7
7
  const worksheet = workbook.addWorksheet('Sheet 1');
8
8
  worksheet.columns = getColumns(table, excelSetting);
@@ -2,5 +2,6 @@ export * from './adapter/index.js';
2
2
  export * from './consts.js';
3
3
  export * from './context.js';
4
4
  export { ColumnFormat, type ExcelSetting } from './excel-setting.js';
5
+ export * from './excel.js';
5
6
  export { default as Table } from './Table.svelte';
6
- export { createActionsColumn } from './util.js';
7
+ export { createActionsColumn, createStaticTable } from './util.js';
@@ -2,5 +2,6 @@ export * from './adapter/index.js';
2
2
  export * from './consts.js';
3
3
  export * from './context.js';
4
4
  export { ColumnFormat } from './excel-setting.js';
5
+ export * from './excel.js';
5
6
  export { default as Table } from './Table.svelte';
6
- export { createActionsColumn } from './util.js';
7
+ export { createActionsColumn, createStaticTable } from './util.js';
@@ -1,4 +1,5 @@
1
- import { type Row } from './adapter/index.js';
1
+ import { type ColumnDef, type Row } from './adapter/index.js';
2
2
  import type { Action } from './types.js';
3
3
  export declare const createCheckedColumn: <T>() => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
4
4
  export declare const createActionsColumn: <T>(getActions: (row: Row<T>) => Action[]) => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
5
+ export declare const createStaticTable: <TData>(columns: ColumnDef<TData, any>[], data: TData[]) => import("./adapter/index.js").Table<TData>;
@@ -1,6 +1,6 @@
1
1
  import ActionsColumn from './ActionsColumn.svelte';
2
2
  import RowCheckBox from './RowCheckBox.svelte';
3
- import { createColumnHelper, renderComponent } from './adapter/index.js';
3
+ import { createColumnHelper, createTable, getCoreRowModel, renderComponent } from './adapter/index.js';
4
4
  export const createCheckedColumn = () => {
5
5
  const columnHelper = createColumnHelper();
6
6
  return columnHelper.display({
@@ -44,3 +44,13 @@ export const createActionsColumn = (getActions) => {
44
44
  })
45
45
  });
46
46
  };
47
+ export const createStaticTable = (columns, data) => {
48
+ return createTable({
49
+ columns,
50
+ data,
51
+ getCoreRowModel: getCoreRowModel(),
52
+ state: {},
53
+ onStateChange: () => { },
54
+ renderFallbackValue: null
55
+ });
56
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwareone/spi-sv5-library",
3
- "version": "1.10.2",
3
+ "version": "1.10.3",
4
4
  "description": "Svelte components",
5
5
  "keywords": [
6
6
  "svelte",
@@ -50,7 +50,6 @@
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@tanstack/table-core": "^8.21.3",
53
- "adaptivecards": "^3.0.5",
54
53
  "exceljs": "^4.4.0",
55
54
  "file-saver": "^2.0.5",
56
55
  "svelte": "^5.0.0",
@@ -64,9 +63,6 @@
64
63
  "zod": {
65
64
  "optional": true
66
65
  },
67
- "adaptivecards": {
68
- "optional": true
69
- },
70
66
  "@tanstack/table-core": {
71
67
  "optional": true
72
68
  },
@@ -78,27 +74,26 @@
78
74
  }
79
75
  },
80
76
  "devDependencies": {
81
- "@sveltejs/adapter-auto": "^7.0.0",
82
- "@sveltejs/adapter-node": "^5.4.0",
83
- "@sveltejs/kit": "^2.48.4",
84
- "@sveltejs/package": "^2.5.4",
85
- "@sveltejs/vite-plugin-svelte": "^6.2.1",
77
+ "@sveltejs/adapter-auto": "^7.0.1",
78
+ "@sveltejs/adapter-node": "^5.5.3",
79
+ "@sveltejs/kit": "^2.53.0",
80
+ "@sveltejs/package": "^2.5.7",
81
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
86
82
  "@tanstack/table-core": "^8.21.3",
87
83
  "@types/file-saver": "^2.0.7",
88
- "adaptivecards": "^3.0.5",
89
84
  "exceljs": "^4.4.0",
90
85
  "file-saver": "^2.0.5",
91
- "prettier": "^3.6.2",
92
- "prettier-plugin-svelte": "^3.4.0",
93
- "publint": "^0.3.15",
94
- "svelte": "^5.43.5",
95
- "svelte-check": "^4.3.3",
96
- "sveltekit-superforms": "^2.28.1",
86
+ "prettier": "^3.8.1",
87
+ "prettier-plugin-svelte": "^3.5.0",
88
+ "publint": "^0.3.17",
89
+ "svelte": "^5.53.3",
90
+ "svelte-check": "^4.4.3",
91
+ "sveltekit-superforms": "^2.30.0",
97
92
  "typescript": "^5.9.3",
98
- "vite": "^6.3.0",
99
- "zod": "^4.1.12"
93
+ "vite": "^7.3.1",
94
+ "zod": "^4.3.6"
100
95
  },
101
96
  "dependencies": {
102
- "@sveltejs/kit": "^2.48.4"
97
+ "@sveltejs/kit": "^2.53.0"
103
98
  }
104
99
  }
@@ -1,210 +0,0 @@
1
- <script lang="ts">
2
- import { onMount } from 'svelte';
3
-
4
- import ChatBotFooter from './ChatBotFooter.svelte';
5
- import ChatBotHeader from './ChatBotHeader.svelte';
6
- import ChatBotMessages from './ChatBotMessages.svelte';
7
- import {
8
- type ChatBotMessage,
9
- type Chat,
10
- type ChatMessage,
11
- type ChatSessionStart,
12
- type UserMessage,
13
- type ChatBotReplyMessage
14
- } from './chatbotState.svelte';
15
-
16
- interface Props {
17
- sendmessage: (chat: Chat) => Promise<ChatBotReplyMessage | undefined>;
18
- title?: string;
19
- }
20
-
21
- let { sendmessage, title = 'Chat Bot' }: Props = $props();
22
-
23
- const CHATBOT_MESSAGES_STORAGE_KEY = 'chatbot-messages';
24
-
25
- let isOpen = $state(false);
26
- let isLoading = $state(false);
27
- let messages = $state<ChatBotMessage[]>([]);
28
-
29
- const initializeChatBot = async () => {
30
- const chat: ChatSessionStart = { type: 'session_init' };
31
- await handleMessage(chat);
32
- };
33
-
34
- const onsend = async (text: string) => {
35
- const chat: ChatMessage = { type: 'text', text };
36
- const userMessage: UserMessage = {
37
- type: 'user',
38
- content: text
39
- };
40
- setMessages(userMessage);
41
- await handleMessage(chat);
42
- };
43
-
44
- const handleMessage = async (chat: Chat) => {
45
- isLoading = true;
46
- const chatBotReplyMessage = await sendmessage(chat);
47
- if (chatBotReplyMessage) setMessages(chatBotReplyMessage);
48
- isLoading = false;
49
- };
50
-
51
- const setMessages = (message: ChatBotMessage) => {
52
- messages = [...messages, message];
53
- storeChatMessages(messages);
54
- };
55
-
56
- const handleClose = () => {
57
- toggleModal();
58
- messages = [];
59
- clearChatMessages();
60
- };
61
-
62
- const toggleModal = () => {
63
- isOpen = !isOpen;
64
- };
65
-
66
- function fetchChatMessages() {
67
- const storedMessages = localStorage.getItem(CHATBOT_MESSAGES_STORAGE_KEY);
68
- const messages: ChatBotMessage[] = storedMessages ? JSON.parse(storedMessages) : [];
69
- return messages;
70
- }
71
-
72
- const storeChatMessages = (messages: ChatBotMessage[]) => {
73
- localStorage.setItem(CHATBOT_MESSAGES_STORAGE_KEY, JSON.stringify(messages));
74
- };
75
-
76
- const clearChatMessages = () => {
77
- localStorage.removeItem(CHATBOT_MESSAGES_STORAGE_KEY);
78
- };
79
-
80
- onMount(() => {
81
- messages = fetchChatMessages();
82
- });
83
-
84
- $effect(() => {
85
- if (isOpen && messages.length === 0) {
86
- initializeChatBot();
87
- }
88
- });
89
- </script>
90
-
91
- <div class="container">
92
- {#if isOpen}
93
- <div class="chatbot-container">
94
- <ChatBotHeader {title} onclose={handleClose} onminimize={toggleModal} />
95
- <div class="chatbot-body">
96
- <ChatBotMessages {messages} {isLoading} oncardaction={handleMessage} />
97
- </div>
98
- <ChatBotFooter {onsend} {isLoading} />
99
- </div>
100
- {:else}
101
- <button class="chatbot-toggle" onclick={toggleModal} aria-label="Open chat">
102
- <span class="material-icons">chat_bubble_outline</span>
103
- </button>
104
- {/if}
105
- </div>
106
-
107
- <style>
108
- .container {
109
- --chatbot-primary: #472aff;
110
- --chatbot-primary-hover: #3520bf;
111
- --chatbot-bg: #ffffff;
112
- --chatbot-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
113
- --chatbot-radius: 16px;
114
- --chatbot-transition: all 0.3s ease;
115
- }
116
-
117
- .chatbot-container {
118
- position: fixed;
119
- bottom: 24px;
120
- right: 24px;
121
- width: 400px;
122
- height: 600px;
123
- display: flex;
124
- flex-direction: column;
125
- border-radius: var(--chatbot-radius);
126
- box-shadow: var(--chatbot-shadow);
127
- background: var(--chatbot-bg);
128
- animation: slideUp 0.3s ease;
129
- transition: var(--chatbot-transition);
130
- z-index: 1000;
131
- }
132
-
133
- .chatbot-body {
134
- flex: 1;
135
- overflow-y: auto;
136
- padding: 10px;
137
- background-color: #f9fafb;
138
- }
139
-
140
- .chatbot-toggle {
141
- position: fixed;
142
- bottom: 24px;
143
- right: 24px;
144
- width: 60px;
145
- height: 60px;
146
- border-radius: 50%;
147
- background: var(--chatbot-primary);
148
- color: var(--chatbot-bg);
149
- border: none;
150
- cursor: pointer;
151
- display: flex;
152
- align-items: center;
153
- justify-content: center;
154
- box-shadow: var(--chatbot-shadow);
155
- transition: var(--chatbot-transition);
156
- z-index: 999;
157
- animation: fadeIn 0.3s ease;
158
- }
159
-
160
- .chatbot-toggle:hover {
161
- background: var(--chatbot-primary-hover);
162
- transform: scale(1.1);
163
- box-shadow: 0 6px 24px rgba(0, 0, 0, 0.2);
164
- }
165
-
166
- .chatbot-toggle:active {
167
- transform: scale(0.95);
168
- }
169
-
170
- .chatbot-toggle .material-icons {
171
- font-size: 28px;
172
- }
173
-
174
- @media (max-width: 480px) {
175
- .chatbot-container {
176
- width: 100vw;
177
- height: 100vh;
178
- bottom: 0;
179
- right: 0;
180
- border-radius: 0;
181
- }
182
-
183
- .chatbot-toggle {
184
- bottom: 16px;
185
- right: 16px;
186
- }
187
- }
188
-
189
- @keyframes slideUp {
190
- from {
191
- transform: translateY(20px);
192
- opacity: 0;
193
- }
194
- to {
195
- transform: translateY(0);
196
- opacity: 1;
197
- }
198
- }
199
-
200
- @keyframes fadeIn {
201
- from {
202
- opacity: 0;
203
- transform: scale(0.8);
204
- }
205
- to {
206
- opacity: 1;
207
- transform: scale(1);
208
- }
209
- }
210
- </style>
@@ -1,8 +0,0 @@
1
- import { type Chat, type ChatBotReplyMessage } from './chatbotState.svelte';
2
- interface Props {
3
- sendmessage: (chat: Chat) => Promise<ChatBotReplyMessage | undefined>;
4
- title?: string;
5
- }
6
- declare const ChatBot: import("svelte").Component<Props, {}, "">;
7
- type ChatBot = ReturnType<typeof ChatBot>;
8
- export default ChatBot;
@@ -1,53 +0,0 @@
1
- <script lang="ts">
2
- import { Input, Button } from '../index.js';
3
-
4
- interface Props {
5
- onsend: (text: string) => Promise<void>;
6
- isLoading: boolean;
7
- }
8
-
9
- let { onsend, isLoading }: Props = $props();
10
-
11
- let message = $state('');
12
-
13
- const handleSend = async () => {
14
- await onsend(message);
15
- message = '';
16
- };
17
-
18
- const handleKeyPress = (event: KeyboardEvent) => {
19
- if (event.key === 'Enter' && !event.shiftKey) {
20
- event.preventDefault();
21
- handleSend();
22
- }
23
- };
24
- </script>
25
-
26
- <div class="chatbot-input">
27
- <div class="input">
28
- <Input
29
- placeholder="Type a message"
30
- bind:value={message}
31
- disableValidationColor
32
- onkeydown={handleKeyPress}
33
- />
34
- </div>
35
- <Button
36
- variant="primary"
37
- variantColor="primary"
38
- disabled={!message || isLoading}
39
- onclick={handleSend}>Send</Button
40
- >
41
- </div>
42
-
43
- <style>
44
- .input {
45
- width: 100%;
46
- }
47
-
48
- .chatbot-input {
49
- display: flex;
50
- gap: 10px;
51
- padding: 10px 14px;
52
- }
53
- </style>
@@ -1,7 +0,0 @@
1
- interface Props {
2
- onsend: (text: string) => Promise<void>;
3
- isLoading: boolean;
4
- }
5
- declare const ChatBotFooter: import("svelte").Component<Props, {}, "">;
6
- type ChatBotFooter = ReturnType<typeof ChatBotFooter>;
7
- export default ChatBotFooter;
@@ -1,66 +0,0 @@
1
- <script lang="ts">
2
- type Props = {
3
- title: string;
4
- onclose: VoidFunction;
5
- onminimize: VoidFunction;
6
- };
7
- let { title, onclose, onminimize }: Props = $props();
8
- </script>
9
-
10
- <div class="chatbot-header">
11
- <h3 class="chatbot-title">{title}</h3>
12
- <div class="header-actions">
13
- <button type="button" class="icon-btn" onclick={onminimize} aria-label="Minimize chat">
14
- <span class="material-icons">remove</span>
15
- </button>
16
- <button type="button" class="icon-btn" onclick={onclose} aria-label="Close chat">
17
- <span class="material-icons">close</span>
18
- </button>
19
- </div>
20
- </div>
21
-
22
- <style>
23
- .chatbot-header {
24
- display: flex;
25
- align-items: center;
26
- justify-content: space-between;
27
- padding: 12px 16px;
28
- background: #472aff;
29
- color: #fff;
30
- border-top-left-radius: 16px;
31
- border-top-right-radius: 16px;
32
- }
33
-
34
- .chatbot-title {
35
- margin: 0;
36
- font-size: 15px;
37
- font-weight: 600;
38
- }
39
-
40
- .header-actions {
41
- display: flex;
42
- gap: 4px;
43
- align-items: center;
44
- }
45
-
46
- .icon-btn {
47
- background: transparent;
48
- border: none;
49
- color: #fff;
50
- cursor: pointer;
51
- padding: 4px;
52
- border-radius: 6px;
53
- display: flex;
54
- align-items: center;
55
- justify-content: center;
56
- transition: background-color 0.2s ease;
57
- }
58
-
59
- .icon-btn:hover {
60
- background-color: rgba(255, 255, 255, 0.2);
61
- }
62
-
63
- .icon-btn .material-icons {
64
- font-size: 18px;
65
- }
66
- </style>
@@ -1,8 +0,0 @@
1
- type Props = {
2
- title: string;
3
- onclose: VoidFunction;
4
- onminimize: VoidFunction;
5
- };
6
- declare const ChatBotHeader: import("svelte").Component<Props, {}, "">;
7
- type ChatBotHeader = ReturnType<typeof ChatBotHeader>;
8
- export default ChatBotHeader;
@@ -1,278 +0,0 @@
1
- <script lang="ts">
2
- import type { Attachment } from 'svelte/attachments';
3
-
4
- import {
5
- Action,
6
- AdaptiveCard,
7
- HostConfig,
8
- SubmitAction,
9
- type IAdaptiveCard
10
- } from 'adaptivecards';
11
-
12
- import type { Chat, ChatBotMessage } from './chatbotState.svelte';
13
-
14
- interface Props {
15
- messages: ChatBotMessage[];
16
- isLoading: boolean;
17
- oncardaction: (chat: Chat) => void;
18
- }
19
-
20
- let { messages, isLoading, oncardaction }: Props = $props();
21
-
22
- const renderAdaptiveCard = (content: IAdaptiveCard): Attachment<HTMLElement> => {
23
- return (element) => {
24
- const adaptiveCard = new AdaptiveCard();
25
-
26
- adaptiveCard.hostConfig = createHostConfig();
27
- adaptiveCard.onExecuteAction = handleActionExecution;
28
- adaptiveCard.parse(content);
29
-
30
- const rendered = adaptiveCard.render();
31
- if (rendered) {
32
- rendered.classList.add('adaptive-card');
33
- element.appendChild(rendered);
34
- }
35
- };
36
- };
37
-
38
- const createHostConfig = () => {
39
- return new HostConfig({
40
- fontFamily: 'Poppins, sans-serif'
41
- });
42
- };
43
-
44
- const handleActionExecution = (action: Action) => {
45
- if (action instanceof SubmitAction) {
46
- const chat = action.data as Chat;
47
- oncardaction(chat);
48
- }
49
- };
50
-
51
- const scrollIntoView: Attachment<HTMLDivElement> = (element: HTMLDivElement) => {
52
- isLoading;
53
- messages.length;
54
- element.scrollIntoView({ behavior: 'smooth', block: 'end' });
55
- };
56
- </script>
57
-
58
- <div {@attach scrollIntoView} class="messages">
59
- {#each messages as message}
60
- {@const isBot = message.type === 'bot'}
61
- {@const isUser = message.type === 'user'}
62
-
63
- <div class={['message', isBot && 'bot', isUser && 'user']}>
64
- {#if isBot && typeof message.content !== 'string'}
65
- <div {@attach renderAdaptiveCard(message.content)}></div>
66
- {:else}
67
- <p class="message-text">{message.content}</p>
68
- {/if}
69
- </div>
70
- {/each}
71
-
72
- {#if isLoading}
73
- <div class="loading">
74
- {#each Array(3) as _}
75
- <span class="loading-dot"></span>
76
- {/each}
77
- </div>
78
- {/if}
79
- </div>
80
-
81
- <style>
82
- .messages {
83
- --color-bg-messages: #f9fafb;
84
- --color-bg-bot: #f8f8ff;
85
- --color-bg-user: #472aff;
86
- --color-text-primary: #1a1a1a;
87
- --color-text-inverse: #ffffff;
88
- --color-border-bot: #543bfa;
89
- --color-scrollbar: #b5b6ff;
90
- --color-scrollbar-hover: #8a8bff;
91
- --color-button-primary: #472aff;
92
- --color-button-hover: #3520bf;
93
- --color-button-active: #2a1894;
94
- --radius-sm: 8px;
95
- --radius-md: 12px;
96
- --spacing-xs: 6px;
97
- --spacing-sm: 10px;
98
- --spacing-md: 14px;
99
- --spacing-lg: 16px;
100
- --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
101
- --shadow-md: 0 2px 10px rgba(0, 0, 0, 0.06);
102
- --shadow-hover: 0 4px 10px rgba(0, 0, 0, 0.08);
103
-
104
- padding: var(--spacing-lg);
105
- display: flex;
106
- flex-direction: column;
107
- gap: var(--spacing-md);
108
- background: var(--color-bg-messages);
109
- border-radius: var(--radius-md);
110
- box-shadow: var(--shadow-md);
111
- }
112
-
113
- .message {
114
- padding: var(--spacing-md);
115
- border-radius: var(--radius-md);
116
- max-width: 95%;
117
- word-break: break-word;
118
- overflow-wrap: break-word;
119
- line-height: 1.5;
120
- animation: fadeIn 0.35s ease forwards;
121
- transition: all 0.25s ease;
122
- }
123
-
124
- .message.user {
125
- align-self: flex-end;
126
- background-color: var(--color-bg-user);
127
- color: var(--color-text-inverse);
128
- border-radius: var(--radius-md) var(--radius-md) 0 var(--radius-md);
129
- max-width: 80%;
130
- box-shadow: var(--shadow-sm);
131
- }
132
-
133
- .message.bot {
134
- align-self: flex-start;
135
- background-color: var(--color-bg-bot);
136
- color: var(--color-text-primary);
137
- border-radius: var(--radius-md) var(--radius-md) var(--radius-md) 0;
138
- box-shadow: var(--shadow-sm);
139
- border-left: 4px solid var(--color-border-bot);
140
- }
141
-
142
- .message-text {
143
- margin: 0;
144
- line-height: 1.4;
145
- }
146
-
147
- .loading {
148
- display: flex;
149
- gap: var(--spacing-xs);
150
- padding: var(--spacing-sm);
151
- }
152
-
153
- .loading-dot {
154
- width: 8px;
155
- height: 8px;
156
- border-radius: 50%;
157
- background-color: var(--color-border-bot);
158
- animation: bounce 1.4s infinite ease-in-out both;
159
- }
160
-
161
- .loading-dot:nth-child(1) {
162
- animation-delay: -0.32s;
163
- }
164
-
165
- .loading-dot:nth-child(2) {
166
- animation-delay: -0.16s;
167
- }
168
-
169
- :global(.adaptive-card),
170
- :global(.adaptive-card .ac-container),
171
- :global(.adaptive-card .ac-columnSet),
172
- :global(.adaptive-card .ac-column),
173
- :global(.adaptive-card .ac-actionSet) {
174
- width: 100%;
175
- max-width: 100%;
176
- margin: 0;
177
- padding: 0;
178
- box-sizing: border-box;
179
- }
180
-
181
- :global(.adaptive-card .ac-textBlock) {
182
- margin-bottom: var(--spacing-xs);
183
- line-height: 1.5;
184
- word-break: break-word;
185
- }
186
-
187
- :global(.adaptive-card .ac-pushButton),
188
- :global(.adaptive-card button),
189
- :global(.adaptive-card .ac-actionSet .ac-button) {
190
- all: unset;
191
- box-sizing: border-box;
192
- display: inline-block;
193
- text-align: center;
194
- padding: 12px 16px;
195
- border-radius: var(--radius-sm);
196
- width: 100%;
197
- cursor: pointer;
198
- background: var(--color-button-primary);
199
- color: var(--color-text-inverse);
200
- font-size: 14px;
201
- font-weight: 400;
202
- line-height: 1.4;
203
- min-height: 44px;
204
- box-shadow: var(--shadow-sm);
205
- transition:
206
- transform 0.2s ease,
207
- box-shadow 0.2s ease,
208
- background-color 0.2s ease;
209
- }
210
-
211
- :global(.adaptive-card .ac-pushButton:hover),
212
- :global(.adaptive-card button:hover),
213
- :global(.adaptive-card .ac-button:hover) {
214
- background: var(--color-button-hover);
215
- transform: translateY(-1px);
216
- box-shadow: var(--shadow-hover);
217
- }
218
-
219
- :global(.adaptive-card .ac-pushButton:active),
220
- :global(.adaptive-card button:active),
221
- :global(.adaptive-card .ac-button:active) {
222
- background: var(--color-button-active);
223
- transform: translateY(0);
224
- box-shadow: none;
225
- }
226
-
227
- :global(.adaptive-card .ac-actionSet) {
228
- display: flex;
229
- flex-wrap: wrap;
230
- justify-content: center;
231
- gap: var(--spacing-sm);
232
- }
233
-
234
- :global(.adaptive-card .ac-actionSet .ac-pushButton),
235
- :global(.adaptive-card .ac-actionSet button),
236
- :global(.adaptive-card .ac-actionSet .ac-button) {
237
- max-width: 280px;
238
- text-align: center;
239
- margin: 0 auto;
240
- }
241
-
242
- :global(.adaptive-card .ac-actionSet.faq-buttons .ac-pushButton),
243
- :global(.adaptive-card .ac-actionSet.faq-buttons button),
244
- :global(.adaptive-card .ac-actionSet.faq-buttons .ac-button) {
245
- width: 100%;
246
- max-width: 100%;
247
- text-align: left;
248
- }
249
-
250
- @media (min-width: 640px) {
251
- :global(.adaptive-card .ac-actionSet) {
252
- flex-direction: column;
253
- align-items: stretch;
254
- }
255
- }
256
-
257
- @keyframes fadeIn {
258
- from {
259
- opacity: 0;
260
- transform: translateY(10px);
261
- }
262
- to {
263
- opacity: 1;
264
- transform: translateY(0);
265
- }
266
- }
267
-
268
- @keyframes bounce {
269
- 0%,
270
- 80%,
271
- 100% {
272
- transform: scale(0);
273
- }
274
- 40% {
275
- transform: scale(1);
276
- }
277
- }
278
- </style>
@@ -1,9 +0,0 @@
1
- import type { Chat, ChatBotMessage } from './chatbotState.svelte';
2
- interface Props {
3
- messages: ChatBotMessage[];
4
- isLoading: boolean;
5
- oncardaction: (chat: Chat) => void;
6
- }
7
- declare const ChatBotMessages: import("svelte").Component<Props, {}, "">;
8
- type ChatBotMessages = ReturnType<typeof ChatBotMessages>;
9
- export default ChatBotMessages;
@@ -1,27 +0,0 @@
1
- import type { IAdaptiveCard } from 'adaptivecards';
2
- export interface UserMessage {
3
- type: 'user';
4
- content: string;
5
- }
6
- export interface ChatBotReplyMessage {
7
- type: 'bot';
8
- content: IAdaptiveCard | string;
9
- }
10
- export type ChatBotMessage = UserMessage | ChatBotReplyMessage;
11
- export interface ChatModuleSelector {
12
- type: 'module_select';
13
- module: string;
14
- }
15
- export interface ChatFAQSelector {
16
- type: 'faq_select';
17
- module: string;
18
- question: string;
19
- }
20
- export interface ChatMessage {
21
- type: 'text';
22
- text: string;
23
- }
24
- export interface ChatSessionStart {
25
- type: 'session_init';
26
- }
27
- export type Chat = ChatModuleSelector | ChatFAQSelector | ChatSessionStart | ChatMessage;
@@ -1 +0,0 @@
1
- export {};