@d34dman/flowdrop 0.0.29 → 0.0.31
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/App.svelte +54 -6
- package/dist/components/NodeSidebar.svelte +17 -9
- package/dist/components/SchemaForm.svelte +14 -14
- package/dist/components/SchemaForm.svelte.d.ts +1 -1
- package/dist/components/WorkflowEditor.svelte +4 -0
- package/dist/components/form/FormFieldLight.svelte +66 -66
- package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
- package/dist/components/form/types.d.ts +1 -1
- package/dist/components/nodes/ToolNode.svelte +23 -8
- package/dist/components/playground/ChatPanel.svelte +523 -0
- package/dist/components/playground/ChatPanel.svelte.d.ts +20 -0
- package/dist/components/playground/ExecutionLogs.svelte +486 -0
- package/dist/components/playground/ExecutionLogs.svelte.d.ts +14 -0
- package/dist/components/playground/InputCollector.svelte +444 -0
- package/dist/components/playground/InputCollector.svelte.d.ts +16 -0
- package/dist/components/playground/MessageBubble.svelte +398 -0
- package/dist/components/playground/MessageBubble.svelte.d.ts +15 -0
- package/dist/components/playground/Playground.svelte +851 -0
- package/dist/components/playground/Playground.svelte.d.ts +25 -0
- package/dist/components/playground/SessionManager.svelte +537 -0
- package/dist/components/playground/SessionManager.svelte.d.ts +20 -0
- package/dist/config/endpoints.d.ts +16 -0
- package/dist/config/endpoints.js +9 -0
- package/dist/core/index.d.ts +25 -23
- package/dist/core/index.js +13 -12
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.js +2 -2
- package/dist/editor/index.d.ts +57 -49
- package/dist/editor/index.js +52 -42
- package/dist/form/code.d.ts +4 -4
- package/dist/form/code.js +11 -11
- package/dist/form/fieldRegistry.d.ts +2 -2
- package/dist/form/fieldRegistry.js +8 -10
- package/dist/form/full.d.ts +5 -5
- package/dist/form/full.js +7 -7
- package/dist/form/index.d.ts +16 -16
- package/dist/form/index.js +14 -14
- package/dist/form/markdown.d.ts +3 -3
- package/dist/form/markdown.js +6 -6
- package/dist/index.d.ts +6 -4
- package/dist/index.js +9 -4
- package/dist/playground/index.d.ts +92 -0
- package/dist/playground/index.js +114 -0
- package/dist/playground/mount.d.ts +183 -0
- package/dist/playground/mount.js +178 -0
- package/dist/services/playgroundService.d.ts +129 -0
- package/dist/services/playgroundService.js +317 -0
- package/dist/stores/playgroundStore.d.ts +199 -0
- package/dist/stores/playgroundStore.js +350 -0
- package/dist/styles/base.css +5 -0
- package/dist/types/playground.d.ts +230 -0
- package/dist/types/playground.js +28 -0
- package/dist/utils/colors.d.ts +42 -0
- package/dist/utils/colors.js +77 -0
- package/package.json +6 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<script lang="ts">
|
|
8
8
|
import { Position, Handle } from '@xyflow/svelte';
|
|
9
9
|
import Icon from '@iconify/svelte';
|
|
10
|
-
import { getDataTypeColor } from '../../utils/colors';
|
|
10
|
+
import { getDataTypeColor, getColorVariants } from '../../utils/colors';
|
|
11
11
|
import type { NodeMetadata } from '../../types/index.js';
|
|
12
12
|
|
|
13
13
|
interface ToolNodeParameter {
|
|
@@ -64,6 +64,19 @@
|
|
|
64
64
|
'1.0.0'
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
+
// Generate color variants for theming (light tint for background, border tint for borders)
|
|
68
|
+
let colorVariants = $derived(getColorVariants(toolColor));
|
|
69
|
+
|
|
70
|
+
// Build inline style string for CSS custom properties
|
|
71
|
+
// This allows per-node color overrides while defaulting to global CSS variables
|
|
72
|
+
let nodeStyle = $derived(
|
|
73
|
+
[
|
|
74
|
+
`--flowdrop-tool-node-color: ${colorVariants.base}`,
|
|
75
|
+
`--flowdrop-tool-node-color-light: ${colorVariants.light}`,
|
|
76
|
+
`--flowdrop-tool-node-color-border: ${colorVariants.border}`
|
|
77
|
+
].join('; ')
|
|
78
|
+
);
|
|
79
|
+
|
|
67
80
|
// Check for tool interface ports in metadata
|
|
68
81
|
let hasToolInputPort = $derived(
|
|
69
82
|
props.data.metadata?.inputs?.some((port) => port.dataType === 'tool') || false
|
|
@@ -128,6 +141,7 @@
|
|
|
128
141
|
class:flowdrop-tool-node--selected={props.selected}
|
|
129
142
|
class:flowdrop-tool-node--processing={props.isProcessing}
|
|
130
143
|
class:flowdrop-tool-node--error={props.isError}
|
|
144
|
+
style={nodeStyle}
|
|
131
145
|
onclick={handleClick}
|
|
132
146
|
ondblclick={handleDoubleClick}
|
|
133
147
|
onkeydown={handleKeydown}
|
|
@@ -138,7 +152,7 @@
|
|
|
138
152
|
<div class="flowdrop-tool-node__header">
|
|
139
153
|
<div class="flowdrop-tool-node__header-content">
|
|
140
154
|
<!-- Tool Icon -->
|
|
141
|
-
<div class="flowdrop-tool-node__icon-container"
|
|
155
|
+
<div class="flowdrop-tool-node__icon-container">
|
|
142
156
|
<Icon icon={toolIcon} class="flowdrop-tool-node__icon" />
|
|
143
157
|
</div>
|
|
144
158
|
|
|
@@ -214,7 +228,7 @@
|
|
|
214
228
|
|
|
215
229
|
.flowdrop-tool-node--selected {
|
|
216
230
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
217
|
-
border: 2px solid
|
|
231
|
+
border: 2px solid var(--flowdrop-tool-node-color);
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
.flowdrop-tool-node--processing {
|
|
@@ -228,9 +242,9 @@
|
|
|
228
242
|
|
|
229
243
|
.flowdrop-tool-node__header {
|
|
230
244
|
padding: 1rem;
|
|
231
|
-
background-color:
|
|
245
|
+
background-color: var(--flowdrop-tool-node-color-light);
|
|
232
246
|
border-radius: 0.75rem;
|
|
233
|
-
border: 1px solid
|
|
247
|
+
border: 1px solid var(--flowdrop-tool-node-color-border);
|
|
234
248
|
}
|
|
235
249
|
|
|
236
250
|
.flowdrop-tool-node__header-content {
|
|
@@ -248,6 +262,7 @@
|
|
|
248
262
|
height: 2.5rem;
|
|
249
263
|
border-radius: 0.5rem;
|
|
250
264
|
flex-shrink: 0;
|
|
265
|
+
background-color: var(--flowdrop-tool-node-color);
|
|
251
266
|
}
|
|
252
267
|
|
|
253
268
|
.flowdrop-tool-node__info {
|
|
@@ -271,7 +286,7 @@
|
|
|
271
286
|
}
|
|
272
287
|
|
|
273
288
|
.flowdrop-tool-node__badge {
|
|
274
|
-
background-color:
|
|
289
|
+
background-color: var(--flowdrop-tool-node-color);
|
|
275
290
|
color: white;
|
|
276
291
|
font-size: 0.625rem;
|
|
277
292
|
font-weight: 700;
|
|
@@ -375,11 +390,11 @@
|
|
|
375
390
|
|
|
376
391
|
/* Metadata port hover effects */
|
|
377
392
|
:global(.svelte-flow__node-tool .svelte-flow__handle:hover) {
|
|
378
|
-
box-shadow: 0 0 0 2px
|
|
393
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--flowdrop-tool-node-color) 30%, transparent) !important;
|
|
379
394
|
}
|
|
380
395
|
|
|
381
396
|
:global(.svelte-flow__node-tool .svelte-flow__handle:focus) {
|
|
382
|
-
outline: 2px solid
|
|
397
|
+
outline: 2px solid var(--flowdrop-tool-node-color) !important;
|
|
383
398
|
outline-offset: 2px !important;
|
|
384
399
|
}
|
|
385
400
|
</style>
|
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ChatPanel Component
|
|
3
|
+
|
|
4
|
+
Clean conversational chat interface for the playground.
|
|
5
|
+
Displays messages with chat bubbles and includes a simple input area.
|
|
6
|
+
Styled with BEM syntax for a Langflow-like appearance.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import Icon from '@iconify/svelte';
|
|
11
|
+
import { tick } from 'svelte';
|
|
12
|
+
import MessageBubble from './MessageBubble.svelte';
|
|
13
|
+
import type { PlaygroundMessage } from '../../types/playground.js';
|
|
14
|
+
import {
|
|
15
|
+
messages,
|
|
16
|
+
chatMessages,
|
|
17
|
+
isExecuting,
|
|
18
|
+
sessionStatus,
|
|
19
|
+
currentSession
|
|
20
|
+
} from '../../stores/playgroundStore.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Component props
|
|
24
|
+
*/
|
|
25
|
+
interface Props {
|
|
26
|
+
/** Whether to show timestamps on messages */
|
|
27
|
+
showTimestamps?: boolean;
|
|
28
|
+
/** Whether to auto-scroll to bottom on new messages */
|
|
29
|
+
autoScroll?: boolean;
|
|
30
|
+
/** Placeholder text for the input */
|
|
31
|
+
placeholder?: string;
|
|
32
|
+
/** Callback when user sends a message */
|
|
33
|
+
onSendMessage?: (content: string) => void;
|
|
34
|
+
/** Callback when user requests to stop execution */
|
|
35
|
+
onStopExecution?: () => void;
|
|
36
|
+
/** Whether to show log messages inline (false = hide them) */
|
|
37
|
+
showLogsInline?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let {
|
|
41
|
+
showTimestamps = true,
|
|
42
|
+
autoScroll = true,
|
|
43
|
+
placeholder = 'Type your message...',
|
|
44
|
+
onSendMessage,
|
|
45
|
+
onStopExecution,
|
|
46
|
+
showLogsInline = false
|
|
47
|
+
}: Props = $props();
|
|
48
|
+
|
|
49
|
+
/** Input field value */
|
|
50
|
+
let inputValue = $state('');
|
|
51
|
+
|
|
52
|
+
/** Reference to the messages container for scrolling */
|
|
53
|
+
let messagesContainer = $state<HTMLDivElement>();
|
|
54
|
+
|
|
55
|
+
/** Reference to the input field */
|
|
56
|
+
let inputField = $state<HTMLTextAreaElement>();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Filter messages based on showLogsInline setting
|
|
60
|
+
*/
|
|
61
|
+
const displayMessages = $derived(showLogsInline ? $messages : $chatMessages);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if we should show the welcome state
|
|
65
|
+
*/
|
|
66
|
+
const showWelcome = $derived(!$currentSession && displayMessages.length === 0);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if we should show the empty chat state (session exists but no messages)
|
|
70
|
+
*/
|
|
71
|
+
const showEmptyChat = $derived($currentSession && displayMessages.length === 0);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Handle sending a message
|
|
75
|
+
*/
|
|
76
|
+
function handleSend(): void {
|
|
77
|
+
const trimmedValue = inputValue.trim();
|
|
78
|
+
if (!trimmedValue || $isExecuting) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onSendMessage?.(trimmedValue);
|
|
83
|
+
inputValue = '';
|
|
84
|
+
|
|
85
|
+
// Reset textarea height
|
|
86
|
+
if (inputField) {
|
|
87
|
+
inputField.style.height = 'auto';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Re-focus the input
|
|
91
|
+
tick().then(() => {
|
|
92
|
+
inputField?.focus();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Handle keyboard events in the input
|
|
98
|
+
*/
|
|
99
|
+
function handleKeydown(event: KeyboardEvent): void {
|
|
100
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
handleSend();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Handle stop execution
|
|
108
|
+
*/
|
|
109
|
+
function handleStop(): void {
|
|
110
|
+
onStopExecution?.();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Auto-scroll to bottom when messages change
|
|
115
|
+
*/
|
|
116
|
+
$effect(() => {
|
|
117
|
+
if (autoScroll && messagesContainer && displayMessages.length > 0) {
|
|
118
|
+
tick().then(() => {
|
|
119
|
+
if (messagesContainer) {
|
|
120
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Auto-resize textarea based on content
|
|
128
|
+
*/
|
|
129
|
+
function handleInput(): void {
|
|
130
|
+
if (inputField) {
|
|
131
|
+
inputField.style.height = 'auto';
|
|
132
|
+
inputField.style.height = `${Math.min(inputField.scrollHeight, 120)}px`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<div class="chat-panel">
|
|
138
|
+
<!-- Messages Container -->
|
|
139
|
+
<div class="chat-panel__messages" bind:this={messagesContainer}>
|
|
140
|
+
{#if showWelcome}
|
|
141
|
+
<!-- Welcome State (no session) -->
|
|
142
|
+
<div class="chat-panel__welcome">
|
|
143
|
+
<div class="chat-panel__welcome-icon">
|
|
144
|
+
<svg
|
|
145
|
+
width="48"
|
|
146
|
+
height="48"
|
|
147
|
+
viewBox="0 0 48 48"
|
|
148
|
+
fill="none"
|
|
149
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
150
|
+
>
|
|
151
|
+
<path
|
|
152
|
+
d="M8 16L24 8L40 16V32L24 40L8 32V16Z"
|
|
153
|
+
stroke="currentColor"
|
|
154
|
+
stroke-width="2"
|
|
155
|
+
stroke-linejoin="round"
|
|
156
|
+
/>
|
|
157
|
+
<path
|
|
158
|
+
d="M8 16L24 24L40 16"
|
|
159
|
+
stroke="currentColor"
|
|
160
|
+
stroke-width="2"
|
|
161
|
+
stroke-linejoin="round"
|
|
162
|
+
/>
|
|
163
|
+
<path d="M24 24V40" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
164
|
+
<path d="M16 12L32 20" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
165
|
+
<path d="M16 36L32 28" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
166
|
+
</svg>
|
|
167
|
+
</div>
|
|
168
|
+
<h2 class="chat-panel__welcome-title">New chat</h2>
|
|
169
|
+
<p class="chat-panel__welcome-text">Test your flow with a chat prompt</p>
|
|
170
|
+
</div>
|
|
171
|
+
{:else if showEmptyChat}
|
|
172
|
+
<!-- Empty Chat State (session exists but no messages) -->
|
|
173
|
+
<div class="chat-panel__welcome">
|
|
174
|
+
<div class="chat-panel__welcome-icon">
|
|
175
|
+
<svg
|
|
176
|
+
width="48"
|
|
177
|
+
height="48"
|
|
178
|
+
viewBox="0 0 48 48"
|
|
179
|
+
fill="none"
|
|
180
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
181
|
+
>
|
|
182
|
+
<path
|
|
183
|
+
d="M8 16L24 8L40 16V32L24 40L8 32V16Z"
|
|
184
|
+
stroke="currentColor"
|
|
185
|
+
stroke-width="2"
|
|
186
|
+
stroke-linejoin="round"
|
|
187
|
+
/>
|
|
188
|
+
<path
|
|
189
|
+
d="M8 16L24 24L40 16"
|
|
190
|
+
stroke="currentColor"
|
|
191
|
+
stroke-width="2"
|
|
192
|
+
stroke-linejoin="round"
|
|
193
|
+
/>
|
|
194
|
+
<path d="M24 24V40" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
195
|
+
<path d="M16 12L32 20" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
196
|
+
<path d="M16 36L32 28" stroke="currentColor" stroke-width="2" stroke-linejoin="round" />
|
|
197
|
+
</svg>
|
|
198
|
+
</div>
|
|
199
|
+
<h2 class="chat-panel__welcome-title">New chat</h2>
|
|
200
|
+
<p class="chat-panel__welcome-text">Test your flow with a chat prompt</p>
|
|
201
|
+
</div>
|
|
202
|
+
{:else}
|
|
203
|
+
<!-- Messages -->
|
|
204
|
+
{#each displayMessages as message, index (message.id)}
|
|
205
|
+
<MessageBubble
|
|
206
|
+
{message}
|
|
207
|
+
showTimestamp={showTimestamps}
|
|
208
|
+
isLast={index === displayMessages.length - 1}
|
|
209
|
+
/>
|
|
210
|
+
{/each}
|
|
211
|
+
|
|
212
|
+
{#if $isExecuting}
|
|
213
|
+
<div class="chat-panel__typing">
|
|
214
|
+
<div class="chat-panel__typing-indicator">
|
|
215
|
+
<span></span>
|
|
216
|
+
<span></span>
|
|
217
|
+
<span></span>
|
|
218
|
+
</div>
|
|
219
|
+
<span class="chat-panel__typing-text">Processing...</span>
|
|
220
|
+
</div>
|
|
221
|
+
{/if}
|
|
222
|
+
{/if}
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<!-- Input Area -->
|
|
226
|
+
<div class="chat-panel__input-area">
|
|
227
|
+
<div class="chat-panel__input-container">
|
|
228
|
+
<div class="chat-panel__input-wrapper">
|
|
229
|
+
<textarea
|
|
230
|
+
bind:this={inputField}
|
|
231
|
+
bind:value={inputValue}
|
|
232
|
+
class="chat-panel__input"
|
|
233
|
+
{placeholder}
|
|
234
|
+
rows="1"
|
|
235
|
+
disabled={$isExecuting}
|
|
236
|
+
onkeydown={handleKeydown}
|
|
237
|
+
oninput={handleInput}
|
|
238
|
+
></textarea>
|
|
239
|
+
|
|
240
|
+
<!-- Attachment button placeholder -->
|
|
241
|
+
<button type="button" class="chat-panel__attachment-btn" title="Attach file" disabled>
|
|
242
|
+
<Icon icon="mdi:image-outline" />
|
|
243
|
+
</button>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
{#if $sessionStatus === 'running' || $isExecuting}
|
|
247
|
+
<button
|
|
248
|
+
type="button"
|
|
249
|
+
class="chat-panel__stop-btn"
|
|
250
|
+
onclick={handleStop}
|
|
251
|
+
title="Stop execution"
|
|
252
|
+
>
|
|
253
|
+
<Icon icon="mdi:stop" />
|
|
254
|
+
Stop
|
|
255
|
+
</button>
|
|
256
|
+
{:else}
|
|
257
|
+
<button
|
|
258
|
+
type="button"
|
|
259
|
+
class="chat-panel__send-btn"
|
|
260
|
+
onclick={handleSend}
|
|
261
|
+
disabled={!inputValue.trim()}
|
|
262
|
+
title="Send message"
|
|
263
|
+
>
|
|
264
|
+
Send
|
|
265
|
+
</button>
|
|
266
|
+
{/if}
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<style>
|
|
272
|
+
.chat-panel {
|
|
273
|
+
display: flex;
|
|
274
|
+
flex-direction: column;
|
|
275
|
+
height: 100%;
|
|
276
|
+
background-color: #ffffff;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Messages Container */
|
|
280
|
+
.chat-panel__messages {
|
|
281
|
+
flex: 1;
|
|
282
|
+
overflow-y: auto;
|
|
283
|
+
padding: 1.5rem;
|
|
284
|
+
scroll-behavior: smooth;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Welcome State */
|
|
288
|
+
.chat-panel__welcome {
|
|
289
|
+
display: flex;
|
|
290
|
+
flex-direction: column;
|
|
291
|
+
align-items: center;
|
|
292
|
+
justify-content: center;
|
|
293
|
+
height: 100%;
|
|
294
|
+
text-align: center;
|
|
295
|
+
padding: 2rem;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.chat-panel__welcome-icon {
|
|
299
|
+
display: flex;
|
|
300
|
+
align-items: center;
|
|
301
|
+
justify-content: center;
|
|
302
|
+
width: 80px;
|
|
303
|
+
height: 80px;
|
|
304
|
+
margin-bottom: 1.5rem;
|
|
305
|
+
color: #1f2937;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.chat-panel__welcome-icon svg {
|
|
309
|
+
width: 100%;
|
|
310
|
+
height: 100%;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.chat-panel__welcome-title {
|
|
314
|
+
font-size: 1.5rem;
|
|
315
|
+
font-weight: 600;
|
|
316
|
+
color: #1f2937;
|
|
317
|
+
margin: 0 0 0.5rem 0;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.chat-panel__welcome-text {
|
|
321
|
+
font-size: 1rem;
|
|
322
|
+
color: #6b7280;
|
|
323
|
+
margin: 0;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Typing Indicator */
|
|
327
|
+
.chat-panel__typing {
|
|
328
|
+
display: flex;
|
|
329
|
+
align-items: center;
|
|
330
|
+
gap: 0.5rem;
|
|
331
|
+
padding: 0.75rem 1rem;
|
|
332
|
+
margin-top: 0.5rem;
|
|
333
|
+
background-color: #f3f4f6;
|
|
334
|
+
border-radius: 1rem;
|
|
335
|
+
width: fit-content;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.chat-panel__typing-indicator {
|
|
339
|
+
display: flex;
|
|
340
|
+
gap: 0.25rem;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.chat-panel__typing-indicator span {
|
|
344
|
+
width: 0.375rem;
|
|
345
|
+
height: 0.375rem;
|
|
346
|
+
background-color: #9ca3af;
|
|
347
|
+
border-radius: 50%;
|
|
348
|
+
animation: bounce 1.4s ease-in-out infinite;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.chat-panel__typing-indicator span:nth-child(1) {
|
|
352
|
+
animation-delay: 0s;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.chat-panel__typing-indicator span:nth-child(2) {
|
|
356
|
+
animation-delay: 0.2s;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.chat-panel__typing-indicator span:nth-child(3) {
|
|
360
|
+
animation-delay: 0.4s;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@keyframes bounce {
|
|
364
|
+
0%,
|
|
365
|
+
60%,
|
|
366
|
+
100% {
|
|
367
|
+
transform: translateY(0);
|
|
368
|
+
}
|
|
369
|
+
30% {
|
|
370
|
+
transform: translateY(-0.25rem);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.chat-panel__typing-text {
|
|
375
|
+
font-size: 0.8125rem;
|
|
376
|
+
color: #6b7280;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/* Input Area */
|
|
380
|
+
.chat-panel__input-area {
|
|
381
|
+
padding: 1rem 1.5rem 1.5rem;
|
|
382
|
+
background-color: #ffffff;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.chat-panel__input-container {
|
|
386
|
+
display: flex;
|
|
387
|
+
align-items: flex-end;
|
|
388
|
+
gap: 0.75rem;
|
|
389
|
+
max-width: 800px;
|
|
390
|
+
margin: 0 auto;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.chat-panel__input-wrapper {
|
|
394
|
+
flex: 1;
|
|
395
|
+
display: flex;
|
|
396
|
+
align-items: flex-end;
|
|
397
|
+
background-color: #ffffff;
|
|
398
|
+
border: 1px solid #e5e7eb;
|
|
399
|
+
border-radius: 0.75rem;
|
|
400
|
+
padding: 0.625rem 0.75rem;
|
|
401
|
+
transition:
|
|
402
|
+
border-color 0.15s ease,
|
|
403
|
+
box-shadow 0.15s ease;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.chat-panel__input-wrapper:focus-within {
|
|
407
|
+
border-color: #6366f1;
|
|
408
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.chat-panel__input {
|
|
412
|
+
flex: 1;
|
|
413
|
+
border: none;
|
|
414
|
+
outline: none;
|
|
415
|
+
resize: none;
|
|
416
|
+
font-family: inherit;
|
|
417
|
+
font-size: 0.9375rem;
|
|
418
|
+
line-height: 1.5;
|
|
419
|
+
max-height: 120px;
|
|
420
|
+
background: transparent;
|
|
421
|
+
color: #1f2937;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.chat-panel__input::placeholder {
|
|
425
|
+
color: #9ca3af;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.chat-panel__input:disabled {
|
|
429
|
+
cursor: not-allowed;
|
|
430
|
+
opacity: 0.6;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.chat-panel__attachment-btn {
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
justify-content: center;
|
|
437
|
+
width: 2rem;
|
|
438
|
+
height: 2rem;
|
|
439
|
+
border: none;
|
|
440
|
+
border-radius: 0.375rem;
|
|
441
|
+
background: transparent;
|
|
442
|
+
color: #9ca3af;
|
|
443
|
+
cursor: pointer;
|
|
444
|
+
transition: all 0.15s ease;
|
|
445
|
+
flex-shrink: 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.chat-panel__attachment-btn:hover:not(:disabled) {
|
|
449
|
+
color: #6b7280;
|
|
450
|
+
background-color: #f3f4f6;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.chat-panel__attachment-btn:disabled {
|
|
454
|
+
opacity: 0.5;
|
|
455
|
+
cursor: not-allowed;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.chat-panel__send-btn {
|
|
459
|
+
display: flex;
|
|
460
|
+
align-items: center;
|
|
461
|
+
justify-content: center;
|
|
462
|
+
padding: 0.625rem 1.25rem;
|
|
463
|
+
border: none;
|
|
464
|
+
border-radius: 0.5rem;
|
|
465
|
+
background-color: #1f2937;
|
|
466
|
+
color: #ffffff;
|
|
467
|
+
font-size: 0.875rem;
|
|
468
|
+
font-weight: 500;
|
|
469
|
+
cursor: pointer;
|
|
470
|
+
transition: all 0.15s ease;
|
|
471
|
+
flex-shrink: 0;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.chat-panel__send-btn:hover:not(:disabled) {
|
|
475
|
+
background-color: #374151;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.chat-panel__send-btn:disabled {
|
|
479
|
+
background-color: #e5e7eb;
|
|
480
|
+
color: #9ca3af;
|
|
481
|
+
cursor: not-allowed;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.chat-panel__stop-btn {
|
|
485
|
+
display: flex;
|
|
486
|
+
align-items: center;
|
|
487
|
+
gap: 0.375rem;
|
|
488
|
+
padding: 0.625rem 1rem;
|
|
489
|
+
border: none;
|
|
490
|
+
border-radius: 0.5rem;
|
|
491
|
+
background-color: #ef4444;
|
|
492
|
+
color: #ffffff;
|
|
493
|
+
font-size: 0.875rem;
|
|
494
|
+
font-weight: 500;
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
transition: background-color 0.15s ease;
|
|
497
|
+
flex-shrink: 0;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.chat-panel__stop-btn:hover {
|
|
501
|
+
background-color: #dc2626;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/* Responsive */
|
|
505
|
+
@media (max-width: 640px) {
|
|
506
|
+
.chat-panel__messages {
|
|
507
|
+
padding: 1rem;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.chat-panel__input-area {
|
|
511
|
+
padding: 0.75rem 1rem 1rem;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.chat-panel__input-container {
|
|
515
|
+
gap: 0.5rem;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.chat-panel__send-btn,
|
|
519
|
+
.chat-panel__stop-btn {
|
|
520
|
+
padding: 0.5rem 1rem;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component props
|
|
3
|
+
*/
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Whether to show timestamps on messages */
|
|
6
|
+
showTimestamps?: boolean;
|
|
7
|
+
/** Whether to auto-scroll to bottom on new messages */
|
|
8
|
+
autoScroll?: boolean;
|
|
9
|
+
/** Placeholder text for the input */
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
/** Callback when user sends a message */
|
|
12
|
+
onSendMessage?: (content: string) => void;
|
|
13
|
+
/** Callback when user requests to stop execution */
|
|
14
|
+
onStopExecution?: () => void;
|
|
15
|
+
/** Whether to show log messages inline (false = hide them) */
|
|
16
|
+
showLogsInline?: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare const ChatPanel: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type ChatPanel = ReturnType<typeof ChatPanel>;
|
|
20
|
+
export default ChatPanel;
|