@makolabs/ripple 0.4.1-0 → 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.
Files changed (59) hide show
  1. package/README.md +165 -205
  2. package/dist/adapters/ai/OpenAIAdapter.d.ts +115 -0
  3. package/dist/adapters/ai/OpenAIAdapter.js +568 -0
  4. package/dist/adapters/ai/index.d.ts +3 -0
  5. package/dist/adapters/ai/index.js +3 -0
  6. package/dist/adapters/ai/types.d.ts +108 -0
  7. package/dist/adapters/ai/types.js +31 -0
  8. package/dist/adapters/storage/BaseAdapter.js +31 -31
  9. package/dist/ai/AIChatInterface.svelte +435 -0
  10. package/dist/ai/AIChatInterface.svelte.d.ts +18 -0
  11. package/dist/ai/ChatInput.svelte +211 -0
  12. package/dist/ai/ChatInput.svelte.d.ts +18 -0
  13. package/dist/ai/CodeRenderer.svelte +174 -0
  14. package/dist/ai/CodeRenderer.svelte.d.ts +8 -0
  15. package/dist/ai/ComposeDropdown.svelte +171 -0
  16. package/dist/ai/ComposeDropdown.svelte.d.ts +9 -0
  17. package/dist/ai/MermaidRenderer.svelte +89 -0
  18. package/dist/ai/MermaidRenderer.svelte.d.ts +7 -0
  19. package/dist/ai/MessageBox.svelte +403 -0
  20. package/dist/ai/MessageBox.svelte.d.ts +12 -0
  21. package/dist/ai/ThinkingDisplay.svelte +275 -0
  22. package/dist/ai/ThinkingDisplay.svelte.d.ts +9 -0
  23. package/dist/ai/ai-chat-interface.d.ts +161 -0
  24. package/dist/ai/ai-chat-interface.js +63 -0
  25. package/dist/ai/content-detector.d.ts +41 -0
  26. package/dist/ai/content-detector.js +153 -0
  27. package/dist/config/ai.d.ts +13 -0
  28. package/dist/config/ai.js +43 -0
  29. package/dist/elements/accordion/accordion.js +1 -1
  30. package/dist/elements/badge/Badge.svelte +14 -3
  31. package/dist/elements/dropdown/Dropdown.svelte +2 -2
  32. package/dist/elements/dropdown/Select.svelte +1 -1
  33. package/dist/elements/progress/Progress.svelte +7 -10
  34. package/dist/file-browser/FileBrowser.svelte +1 -1
  35. package/dist/forms/DateRange.svelte +18 -16
  36. package/dist/forms/NumberInput.svelte +1 -1
  37. package/dist/forms/RadioInputs.svelte +1 -1
  38. package/dist/forms/RadioPill.svelte +1 -1
  39. package/dist/forms/Tags.svelte +2 -2
  40. package/dist/helper/date.d.ts +1 -0
  41. package/dist/helper/date.js +6 -0
  42. package/dist/index.d.ts +65 -1
  43. package/dist/index.js +11 -0
  44. package/dist/layout/activity-list/ActivityList.svelte +94 -0
  45. package/dist/layout/activity-list/ActivityList.svelte.d.ts +4 -0
  46. package/dist/layout/activity-list/activity-list.d.ts +152 -0
  47. package/dist/layout/activity-list/activity-list.js +59 -0
  48. package/dist/layout/card/Card.svelte +1 -5
  49. package/dist/layout/card/metric-card.d.ts +18 -18
  50. package/dist/layout/table/Cells.svelte +1 -7
  51. package/dist/layout/table/Cells.svelte.d.ts +1 -1
  52. package/dist/modal/Modal.svelte +4 -2
  53. package/dist/modal/Modal.svelte.d.ts +1 -1
  54. package/dist/modal/modal.d.ts +19 -18
  55. package/dist/modal/modal.js +7 -6
  56. package/dist/sonner/sonner.svelte +1 -7
  57. package/dist/types/markdown.d.ts +14 -0
  58. package/dist/utils/Portal.svelte +1 -1
  59. package/package.json +128 -121
@@ -0,0 +1,211 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { browser } from '$app/environment';
4
+ import { tv } from 'tailwind-variants';
5
+ import ComposeDropdown from './ComposeDropdown.svelte';
6
+ import type { VariantColors } from '../index.js';
7
+
8
+ interface ChatInputProps {
9
+ userInput: string;
10
+ textareaRef?: HTMLTextAreaElement;
11
+ placeholder: string;
12
+ isProcessing: boolean;
13
+ disabled: boolean;
14
+ isAdapterConfigured: boolean;
15
+ color?: VariantColors;
16
+ hasMessages: boolean;
17
+ thinkingMode?: boolean;
18
+ onSubmit: () => void;
19
+ onKeyDown: (event: KeyboardEvent) => void;
20
+ onThinkingToggle?: (enabled: boolean) => void;
21
+ }
22
+
23
+ let {
24
+ userInput = $bindable(),
25
+ textareaRef = $bindable(),
26
+ placeholder,
27
+ isProcessing,
28
+ disabled,
29
+ isAdapterConfigured,
30
+ color = 'primary',
31
+ hasMessages,
32
+ thinkingMode = $bindable(),
33
+ onSubmit,
34
+ onKeyDown,
35
+ onThinkingToggle
36
+ }: ChatInputProps = $props();
37
+
38
+ const textarea = tv({
39
+ base: 'flex-1 rounded-md text-sm placeholder-gray-400 focus:outline-none transition-all duration-200 bg-gray-200/60 border-0 resize-none',
40
+ variants: {
41
+ layout: {
42
+ empty: 'px-6 py-4 min-h-[52px] max-h-[120px]',
43
+ chat: 'px-6 py-3 min-h-[48px] max-h-[393px] overflow-y-auto'
44
+ },
45
+ state: {
46
+ disabled: 'bg-gray-100 cursor-not-allowed text-gray-500',
47
+ enabled: 'hover:bg-gray-200/80 focus:bg-white focus:ring-2 focus:shadow-md'
48
+ }
49
+ },
50
+ compoundVariants: [
51
+ {
52
+ state: 'enabled',
53
+ class: 'focus:ring-primary-500/20'
54
+ }
55
+ ]
56
+ });
57
+
58
+ const sendButton = tv({
59
+ base: 'flex h-12 w-12 items-center justify-center rounded-full transition-all duration-200',
60
+ variants: {
61
+ state: {
62
+ disabled: 'bg-gray-200 text-gray-400 cursor-not-allowed',
63
+ enabled: 'text-white bg-primary-500 hover:bg-primary-600 focus:ring-2 focus:ring-primary-500/20'
64
+ }
65
+ }
66
+ });
67
+
68
+
69
+
70
+ const inputArea = tv({
71
+ variants: {
72
+ layout: {
73
+ empty: 'w-full max-w-3xl',
74
+ chat: 'sticky bottom-0 z-10 flex-shrink-0 bg-white/50 px-6 pt-2 pb-0 backdrop-blur-sm'
75
+ }
76
+ }
77
+ });
78
+
79
+ const inputContainer = tv({
80
+ base: 'flex items-end gap-3',
81
+ variants: {
82
+ layout: {
83
+ empty: '',
84
+ chat: 'mx-auto max-w-4xl'
85
+ }
86
+ }
87
+ });
88
+
89
+ // Computed classes
90
+ const textareaClasses = $derived(
91
+ textarea({
92
+ layout: hasMessages ? 'chat' : 'empty',
93
+ state: disabled || !isAdapterConfigured ? 'disabled' : 'enabled'
94
+ })
95
+ );
96
+
97
+ const sendButtonClasses = $derived(
98
+ sendButton({
99
+ state: disabled || !isAdapterConfigured || isProcessing || !userInput.trim() ? 'disabled' : 'enabled'
100
+ })
101
+ );
102
+
103
+
104
+
105
+ const inputAreaClasses = $derived(
106
+ inputArea({
107
+ layout: hasMessages ? 'chat' : 'empty'
108
+ })
109
+ );
110
+
111
+ const inputContainerClasses = $derived(
112
+ inputContainer({
113
+ layout: hasMessages ? 'chat' : 'empty'
114
+ })
115
+ );
116
+
117
+ // Auto-resize textarea functionality
118
+ function autoResizeTextarea() {
119
+ if (textareaRef) {
120
+ textareaRef.style.height = 'auto';
121
+ textareaRef.style.height = Math.min(textareaRef.scrollHeight, 393) + 'px';
122
+ }
123
+ }
124
+
125
+ // Watch for userInput changes and auto-resize
126
+ $effect(() => {
127
+ if (userInput !== undefined) {
128
+ // Small delay to ensure DOM is updated
129
+ setTimeout(autoResizeTextarea, 0);
130
+ }
131
+ });
132
+
133
+ // Conditional handlers for textarea based on layout
134
+ const textareaHandlers = $derived({
135
+ onkeydown: onKeyDown,
136
+ // Only add auto-resize handlers in chat layout (when messages exist)
137
+ ...(hasMessages && {
138
+ oninput: autoResizeTextarea,
139
+ onpaste: () => setTimeout(autoResizeTextarea, 0)
140
+ })
141
+ });
142
+
143
+ function handleSubmit() {
144
+ onSubmit();
145
+ }
146
+
147
+ onMount(() => {
148
+ // Auto-focus textarea on mount if configured
149
+ if (browser && isAdapterConfigured) {
150
+ setTimeout(() => {
151
+ textareaRef?.focus();
152
+ }, 100);
153
+ }
154
+ });
155
+ </script>
156
+
157
+ <!-- Single Input Area (used by both layouts) -->
158
+ <div class={inputAreaClasses}>
159
+ <div class={inputContainerClasses}>
160
+ <!-- Compose Dropdown -->
161
+ <ComposeDropdown
162
+ {disabled}
163
+ {isAdapterConfigured}
164
+ bind:thinkingMode
165
+ {onThinkingToggle}
166
+ />
167
+
168
+ <textarea
169
+ bind:this={textareaRef}
170
+ bind:value={userInput}
171
+ {...textareaHandlers}
172
+ {placeholder}
173
+ class={textareaClasses}
174
+ rows={1}
175
+ disabled={isProcessing || disabled || !isAdapterConfigured}
176
+ ></textarea>
177
+
178
+ <button
179
+ class={sendButtonClasses}
180
+ onclick={handleSubmit}
181
+ disabled={isProcessing || disabled || !userInput.trim() || !isAdapterConfigured}
182
+ aria-label="Send message"
183
+ >
184
+ {#if isProcessing}
185
+ <svg class="h-5 w-5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
186
+ <path
187
+ stroke-linecap="round"
188
+ stroke-linejoin="round"
189
+ stroke-width="2"
190
+ d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
191
+ />
192
+ </svg>
193
+ {:else}
194
+ <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
195
+ <path
196
+ stroke-linecap="round"
197
+ stroke-linejoin="round"
198
+ stroke-width="2"
199
+ d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
200
+ />
201
+ </svg>
202
+ {/if}
203
+ </button>
204
+ </div>
205
+
206
+ <div class="mt-2 h-6 px-2">
207
+ {#if userInput.trim() && !isProcessing}
208
+ <p class="text-xs text-gray-500">Press Enter to send • Shift+Enter for new line</p>
209
+ {/if}
210
+ </div>
211
+ </div>
@@ -0,0 +1,18 @@
1
+ import type { VariantColors } from '../index.js';
2
+ interface ChatInputProps {
3
+ userInput: string;
4
+ textareaRef?: HTMLTextAreaElement;
5
+ placeholder: string;
6
+ isProcessing: boolean;
7
+ disabled: boolean;
8
+ isAdapterConfigured: boolean;
9
+ color?: VariantColors;
10
+ hasMessages: boolean;
11
+ thinkingMode?: boolean;
12
+ onSubmit: () => void;
13
+ onKeyDown: (event: KeyboardEvent) => void;
14
+ onThinkingToggle?: (enabled: boolean) => void;
15
+ }
16
+ declare const ChatInput: import("svelte").Component<ChatInputProps, {}, "thinkingMode" | "userInput" | "textareaRef">;
17
+ type ChatInput = ReturnType<typeof ChatInput>;
18
+ export default ChatInput;
@@ -0,0 +1,174 @@
1
+ <script lang="ts">
2
+ import Highlight from 'svelte-highlight';
3
+ import { HighlightAuto } from 'svelte-highlight';
4
+
5
+ // Import common languages
6
+ import javascript from 'svelte-highlight/languages/javascript';
7
+ import typescript from 'svelte-highlight/languages/typescript';
8
+ import python from 'svelte-highlight/languages/python';
9
+ import java from 'svelte-highlight/languages/java';
10
+ import cpp from 'svelte-highlight/languages/cpp';
11
+ import csharp from 'svelte-highlight/languages/csharp';
12
+ import php from 'svelte-highlight/languages/php';
13
+ import ruby from 'svelte-highlight/languages/ruby';
14
+ import go from 'svelte-highlight/languages/go';
15
+ import rust from 'svelte-highlight/languages/rust';
16
+ import swift from 'svelte-highlight/languages/swift';
17
+ import kotlin from 'svelte-highlight/languages/kotlin';
18
+ import css from 'svelte-highlight/languages/css';
19
+ import html from 'svelte-highlight/languages/xml';
20
+ import json from 'svelte-highlight/languages/json';
21
+ import yaml from 'svelte-highlight/languages/yaml';
22
+ import sql from 'svelte-highlight/languages/sql';
23
+ import bash from 'svelte-highlight/languages/bash';
24
+ import powershell from 'svelte-highlight/languages/powershell';
25
+ import dockerfile from 'svelte-highlight/languages/dockerfile';
26
+ import markdown from 'svelte-highlight/languages/markdown';
27
+
28
+ // Import a clean dark theme
29
+ import githubDark from 'svelte-highlight/styles/github-dark';
30
+
31
+ interface Props {
32
+ code: string;
33
+ language?: string;
34
+ class?: string;
35
+ }
36
+
37
+ let { code, language = 'text', class: className = '' }: Props = $props();
38
+
39
+ // Language mapping
40
+ const languageMap: Record<string, any> = {
41
+ javascript: javascript,
42
+ js: javascript,
43
+ typescript: typescript,
44
+ ts: typescript,
45
+ python: python,
46
+ py: python,
47
+ java: java,
48
+ cpp: cpp,
49
+ 'c++': cpp,
50
+ csharp: csharp,
51
+ 'c#': csharp,
52
+ php: php,
53
+ ruby: ruby,
54
+ rb: ruby,
55
+ go: go,
56
+ golang: go,
57
+ rust: rust,
58
+ rs: rust,
59
+ swift: swift,
60
+ kotlin: kotlin,
61
+ kt: kotlin,
62
+ css: css,
63
+ html: html,
64
+ xml: html,
65
+ json: json,
66
+ yaml: yaml,
67
+ yml: yaml,
68
+ sql: sql,
69
+ bash: bash,
70
+ sh: bash,
71
+ shell: bash,
72
+ powershell: powershell,
73
+ ps1: powershell,
74
+ dockerfile: dockerfile,
75
+ docker: dockerfile,
76
+ markdown: markdown,
77
+ md: markdown
78
+ };
79
+
80
+ const selectedLanguage = $derived(languageMap[language.toLowerCase()] || null);
81
+ const displayLanguage = $derived(language.toUpperCase());
82
+
83
+ let copied = $state(false);
84
+
85
+ async function copyCode() {
86
+ try {
87
+ await navigator.clipboard.writeText(code);
88
+ copied = true;
89
+ // Reset after 2 seconds
90
+ setTimeout(() => {
91
+ copied = false;
92
+ }, 2000);
93
+ } catch (err) {
94
+ console.error('Failed to copy code:', err);
95
+ }
96
+ }
97
+ </script>
98
+
99
+ <svelte:head>
100
+ {@html githubDark}
101
+ </svelte:head>
102
+
103
+ <div class="code-renderer my-4 overflow-hidden rounded-lg border border-gray-700 bg-gray-900 {className}">
104
+ <!-- Header -->
105
+ <div class="flex items-center justify-between bg-gray-800 px-4 py-2 border-b border-gray-700">
106
+ <span class="text-xs font-medium text-gray-300 uppercase tracking-wide">
107
+ {displayLanguage}
108
+ </span>
109
+ <button
110
+ onclick={copyCode}
111
+ class="flex items-center gap-1.5 rounded px-2 py-1 text-xs transition-all duration-200 {copied
112
+ ? 'text-green-400 border border-green-500 bg-green-500/10'
113
+ : 'text-gray-400 hover:bg-gray-700 hover:text-gray-200'}"
114
+ title={copied ? "Copied!" : "Copy code"}
115
+ >
116
+ {#if copied}
117
+ <!-- Checkmark icon -->
118
+ <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
119
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
120
+ </svg>
121
+ Copied!
122
+ {:else}
123
+ <!-- Copy icon -->
124
+ <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
125
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
126
+ </svg>
127
+ Copy
128
+ {/if}
129
+ </button>
130
+ </div>
131
+
132
+ <!-- Code Content -->
133
+ <div class="relative">
134
+ {#if selectedLanguage}
135
+ <Highlight language={selectedLanguage} {code} />
136
+ {:else}
137
+ <HighlightAuto {code} />
138
+ {/if}
139
+ </div>
140
+ </div>
141
+
142
+ <style>
143
+ /* Override highlight.js styles for consistent theming */
144
+ :global(.code-renderer .hljs) {
145
+ color: #e6edf3 !important;
146
+ margin: 0 !important;
147
+ font-size: 0.875rem;
148
+ line-height: 1.6;
149
+ overflow-x: auto;
150
+ }
151
+
152
+ :global(.code-renderer pre) {
153
+ margin: 0 !important;
154
+ background: transparent !important;
155
+ }
156
+
157
+ /* Ensure consistent scrollbar styling */
158
+ :global(.code-renderer .hljs::-webkit-scrollbar) {
159
+ height: 8px;
160
+ }
161
+
162
+ :global(.code-renderer .hljs::-webkit-scrollbar-track) {
163
+ background: #21262d;
164
+ }
165
+
166
+ :global(.code-renderer .hljs::-webkit-scrollbar-thumb) {
167
+ background: #484f58;
168
+ border-radius: 4px;
169
+ }
170
+
171
+ :global(.code-renderer .hljs::-webkit-scrollbar-thumb:hover) {
172
+ background: #6e7681;
173
+ }
174
+ </style>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ code: string;
3
+ language?: string;
4
+ class?: string;
5
+ }
6
+ declare const CodeRenderer: import("svelte").Component<Props, {}, "">;
7
+ type CodeRenderer = ReturnType<typeof CodeRenderer>;
8
+ export default CodeRenderer;
@@ -0,0 +1,171 @@
1
+ <script lang="ts">
2
+ import { tv } from 'tailwind-variants';
3
+ import Toggle from '../forms/Toggle.svelte';
4
+ import { Size } from '../variants.js';
5
+ import type { VariantColors } from '../index.js';
6
+
7
+ interface ComposeDropdownProps {
8
+ disabled?: boolean;
9
+ isAdapterConfigured?: boolean;
10
+ thinkingMode?: boolean;
11
+ onThinkingToggle?: (enabled: boolean) => void;
12
+ }
13
+
14
+ let {
15
+ disabled = false,
16
+ isAdapterConfigured = true,
17
+ thinkingMode = $bindable(false),
18
+ onThinkingToggle
19
+ }: ComposeDropdownProps = $props();
20
+
21
+ let isOpen = $state(false);
22
+ let dropdownRef: HTMLDivElement | undefined = $state();
23
+
24
+ // Mock models data - will be replaced with real data later
25
+ const models = [
26
+ { id: 'gpt-4', name: 'GPT-4', provider: 'OpenAI' },
27
+ { id: 'gpt-3.5-turbo', name: 'GPT-3.5 Turbo', provider: 'OpenAI' },
28
+ { id: 'claude-3', name: 'Claude 3', provider: 'Anthropic' }
29
+ ];
30
+
31
+ const plusButton = tv({
32
+ base: 'flex h-10 w-10 items-center justify-center rounded-full transition-all duration-200',
33
+ variants: {
34
+ state: {
35
+ disabled: 'bg-gray-100 text-gray-300 cursor-not-allowed',
36
+ enabled: 'bg-gray-200 text-gray-600 hover:bg-gray-300 hover:text-gray-800 focus:ring-2 focus:ring-gray-300/50'
37
+ }
38
+ }
39
+ });
40
+
41
+ const dropdown = tv({
42
+ base: 'absolute bottom-12 left-0 z-50 w-64 bg-white border border-gray-200 rounded-lg shadow-lg py-2',
43
+ variants: {
44
+ visible: {
45
+ true: 'opacity-100 scale-100',
46
+ false: 'opacity-0 scale-95 pointer-events-none'
47
+ }
48
+ }
49
+ });
50
+
51
+ const menuItem = tv({
52
+ base: 'flex items-center px-4 py-2 text-sm transition-colors',
53
+ variants: {
54
+ state: {
55
+ enabled: 'text-gray-700 hover:bg-gray-50 cursor-pointer',
56
+ disabled: 'text-gray-400 cursor-not-allowed'
57
+ },
58
+ layout: {
59
+ default: 'justify-between',
60
+ full: 'justify-start'
61
+ }
62
+ }
63
+ });
64
+
65
+ const plusButtonClasses = $derived(
66
+ plusButton({
67
+ state: disabled || !isAdapterConfigured ? 'disabled' : 'enabled'
68
+ })
69
+ );
70
+
71
+ const dropdownClasses = $derived(
72
+ dropdown({
73
+ visible: isOpen
74
+ })
75
+ );
76
+
77
+ function toggleDropdown() {
78
+ if (disabled || !isAdapterConfigured) return;
79
+ isOpen = !isOpen;
80
+ }
81
+
82
+ // Watch for thinkingMode changes and call the callback
83
+ $effect(() => {
84
+ onThinkingToggle?.(thinkingMode);
85
+ });
86
+
87
+ function closeDropdown() {
88
+ isOpen = false;
89
+ }
90
+
91
+ // Close dropdown when clicking outside
92
+ function handleClickOutside(event: MouseEvent) {
93
+ if (dropdownRef && !dropdownRef.contains(event.target as Node)) {
94
+ closeDropdown();
95
+ }
96
+ }
97
+
98
+ $effect(() => {
99
+ if (isOpen) {
100
+ document.addEventListener('click', handleClickOutside);
101
+ return () => {
102
+ document.removeEventListener('click', handleClickOutside);
103
+ };
104
+ }
105
+ });
106
+ </script>
107
+
108
+ <div class="relative" bind:this={dropdownRef}>
109
+ <!-- Plus Button -->
110
+ <button
111
+ class={plusButtonClasses}
112
+ onclick={toggleDropdown}
113
+ disabled={disabled || !isAdapterConfigured}
114
+ aria-label="Compose options"
115
+ aria-expanded={isOpen}
116
+ >
117
+ <svg
118
+ xmlns="http://www.w3.org/2000/svg"
119
+ width="0.7em"
120
+ height="0.7em"
121
+ viewBox="0 0 20 20"
122
+ class="w-5 h-5"
123
+ >
124
+ <path fill="currentColor" d="M10 2.25a.75.75 0 0 1 .75.75v6.25H17a.75.75 0 0 1 0 1.5h-6.25V17a.75.75 0 0 1-1.5 0v-6.25H3a.75.75 0 0 1 0-1.5h6.25V3a.75.75 0 0 1 .75-.75"/>
125
+ </svg>
126
+ </button>
127
+
128
+ <!-- Dropdown Menu -->
129
+ <div class={dropdownClasses}>
130
+ <!-- Models Section -->
131
+ <div class="px-4 py-2 border-b border-gray-100">
132
+ <h3 class="text-xs font-medium text-gray-500 uppercase tracking-wide">Models</h3>
133
+ </div>
134
+
135
+ {#each models as model}
136
+ <div class={menuItem({ state: 'disabled', layout: 'default' })}>
137
+ <div class="flex flex-col">
138
+ <span class="font-medium">{model.name}</span>
139
+ <span class="text-xs text-gray-400">{model.provider}</span>
140
+ </div>
141
+ <div class="text-xs text-gray-400">Disabled</div>
142
+ </div>
143
+ {/each}
144
+
145
+ <!-- Divider -->
146
+ <div class="border-t border-gray-100 my-2"></div>
147
+
148
+ <!-- Thinking Mode Option -->
149
+ <div class="px-4 py-2 border-b border-gray-100">
150
+ <h3 class="text-xs font-medium text-gray-500 uppercase tracking-wide">Options</h3>
151
+ </div>
152
+
153
+ <div class={menuItem({ state: 'enabled', layout: 'full' }) + ' w-full cursor-pointer'}>
154
+ <div class="flex items-center justify-between w-full">
155
+ <div class="flex flex-col items-start">
156
+ <span class="font-medium">Thinking Mode</span>
157
+ <span class="text-xs text-gray-500">Show reasoning process</span>
158
+ </div>
159
+ <div class="flex items-center ml-4">
160
+ <Toggle
161
+ name="thinking-mode"
162
+ bind:value={thinkingMode}
163
+ size={Size.BASE}
164
+ color="primary"
165
+ class="ml-2"
166
+ />
167
+ </div>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
@@ -0,0 +1,9 @@
1
+ interface ComposeDropdownProps {
2
+ disabled?: boolean;
3
+ isAdapterConfigured?: boolean;
4
+ thinkingMode?: boolean;
5
+ onThinkingToggle?: (enabled: boolean) => void;
6
+ }
7
+ declare const ComposeDropdown: import("svelte").Component<ComposeDropdownProps, {}, "thinkingMode">;
8
+ type ComposeDropdown = ReturnType<typeof ComposeDropdown>;
9
+ export default ComposeDropdown;
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import { Mermaid } from '@friendofsvelte/mermaid';
3
+ import type { MermaidConfig } from '@friendofsvelte/mermaid';
4
+
5
+ interface Props {
6
+ diagram: string;
7
+ class?: string;
8
+ }
9
+
10
+ let { diagram, class: className = '' }: Props = $props();
11
+
12
+ // Mermaid configuration with multiple node colors like your image
13
+ const config: MermaidConfig = {
14
+ theme: 'base',
15
+ themeVariables: {
16
+ // Background and typography
17
+ background: '#ffffff',
18
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
19
+ fontSize: '14px',
20
+
21
+ // Default node styling
22
+ primaryColor: '#E8F4FD',
23
+ primaryTextColor: '#2C3E50',
24
+ primaryBorderColor: '#B8D4F0',
25
+
26
+ // Lines and connections
27
+ lineColor: '#7F8C8D',
28
+ textColor: '#2C3E50',
29
+ defaultLinkColor: '#7F8C8D',
30
+ edgeLabelBackground: '#ffffff',
31
+
32
+ // Color scale for different node types (matching your image)
33
+ cScale0: '#E8F4FD', // Light blue - Frontend code, Tauri build
34
+ cScale1: '#E8F5E8', // Light green - Bundler, App binary
35
+ cScale2: '#FFF2E8', // Light orange - Dist assets
36
+ cScale3: '#F0E8FF', // Light purple - Rust code
37
+ cScale4: '#FFFDE8', // Light yellow - Installer
38
+ cScale5: '#F8F8F8', // Light gray - fallback
39
+ cScale6: '#E0E0E0', // Medium gray - borders
40
+ cScale7: '#2C3E50', // Dark text
41
+ cScale8: '#7F8C8D', // Line color
42
+ cScale9: '#FFFFFF', // White background
43
+
44
+ // Node styling
45
+ nodeBorder: '#B8D4F0',
46
+ nodeTextColor: '#2C3E50'
47
+ },
48
+ flowchart: {
49
+ useMaxWidth: true,
50
+ htmlLabels: true,
51
+ curve: 'basis',
52
+ nodeSpacing: 50,
53
+ rankSpacing: 80,
54
+ padding: 20,
55
+ diagramPadding: 20
56
+ },
57
+ sequence: {
58
+ useMaxWidth: true,
59
+ actorMargin: 50
60
+ },
61
+ gantt: {
62
+ useMaxWidth: true
63
+ }
64
+ };
65
+ </script>
66
+
67
+ <div class="mermaid-rounded">
68
+ <Mermaid string={diagram} {config}>
69
+ {#snippet error(errorObj)}
70
+ <div class="rounded-lg border border-red-200 bg-red-50 p-4">
71
+ <div class="flex items-center gap-2 text-red-800">
72
+ <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
73
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
74
+ </svg>
75
+ <span class="font-medium">Failed to render Mermaid diagram</span>
76
+ </div>
77
+ <p class="mt-2 text-sm text-red-700">${errorObj.message}</p>
78
+ </div>
79
+ {/snippet}
80
+ </Mermaid>
81
+ </div>
82
+
83
+ <style>
84
+ /* Minimal CSS for rounded edges - only what config can't do */
85
+ :global(.mermaid-rounded .node rect) {
86
+ rx: 8px !important;
87
+ ry: 8px !important;
88
+ }
89
+ </style>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ diagram: string;
3
+ class?: string;
4
+ }
5
+ declare const MermaidRenderer: import("svelte").Component<Props, {}, "">;
6
+ type MermaidRenderer = ReturnType<typeof MermaidRenderer>;
7
+ export default MermaidRenderer;