Merge pull request #565 from oTToDev-CE/ui/model-dropdown
Browse files
app/components/chat/BaseChat.tsx
CHANGED
@@ -369,21 +369,6 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
|
369 |
<rect className={classNames(styles.PromptShine)} x="48" y="24" width="70" height="1"></rect>
|
370 |
</svg>
|
371 |
<div>
|
372 |
-
<div className="flex justify-between items-center mb-2">
|
373 |
-
<button
|
374 |
-
onClick={() => setIsModelSettingsCollapsed(!isModelSettingsCollapsed)}
|
375 |
-
className={classNames('flex items-center gap-2 p-2 rounded-lg transition-all', {
|
376 |
-
'bg-bolt-elements-item-backgroundAccent text-bolt-elements-item-contentAccent':
|
377 |
-
isModelSettingsCollapsed,
|
378 |
-
'bg-bolt-elements-item-backgroundDefault text-bolt-elements-item-contentDefault':
|
379 |
-
!isModelSettingsCollapsed,
|
380 |
-
})}
|
381 |
-
>
|
382 |
-
<div className={`i-ph:caret-${isModelSettingsCollapsed ? 'right' : 'down'} text-lg`} />
|
383 |
-
<span>Model Settings</span>
|
384 |
-
</button>
|
385 |
-
</div>
|
386 |
-
|
387 |
<div className={isModelSettingsCollapsed ? 'hidden' : ''}>
|
388 |
<ModelSelector
|
389 |
key={provider?.name + ':' + modelList.length}
|
@@ -491,6 +476,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
|
491 |
<SendButton
|
492 |
show={input.length > 0 || isStreaming || uploadedFiles.length > 0}
|
493 |
isStreaming={isStreaming}
|
|
|
494 |
onClick={(event) => {
|
495 |
if (isStreaming) {
|
496 |
handleStop?.();
|
@@ -541,6 +527,20 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
|
541 |
disabled={isStreaming}
|
542 |
/>
|
543 |
{chatStarted && <ClientOnly>{() => <ExportChatButton exportChat={exportChat} />}</ClientOnly>}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
544 |
</div>
|
545 |
{input.length > 3 ? (
|
546 |
<div className="text-xs text-bolt-elements-textTertiary">
|
|
|
369 |
<rect className={classNames(styles.PromptShine)} x="48" y="24" width="70" height="1"></rect>
|
370 |
</svg>
|
371 |
<div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
<div className={isModelSettingsCollapsed ? 'hidden' : ''}>
|
373 |
<ModelSelector
|
374 |
key={provider?.name + ':' + modelList.length}
|
|
|
476 |
<SendButton
|
477 |
show={input.length > 0 || isStreaming || uploadedFiles.length > 0}
|
478 |
isStreaming={isStreaming}
|
479 |
+
disabled={enabledProviders.length === 0}
|
480 |
onClick={(event) => {
|
481 |
if (isStreaming) {
|
482 |
handleStop?.();
|
|
|
527 |
disabled={isStreaming}
|
528 |
/>
|
529 |
{chatStarted && <ClientOnly>{() => <ExportChatButton exportChat={exportChat} />}</ClientOnly>}
|
530 |
+
<IconButton
|
531 |
+
title="Model Settings"
|
532 |
+
className={classNames('transition-all flex items-center gap-1', {
|
533 |
+
'bg-bolt-elements-item-backgroundAccent text-bolt-elements-item-contentAccent':
|
534 |
+
isModelSettingsCollapsed,
|
535 |
+
'bg-bolt-elements-item-backgroundDefault text-bolt-elements-item-contentDefault':
|
536 |
+
!isModelSettingsCollapsed,
|
537 |
+
})}
|
538 |
+
onClick={() => setIsModelSettingsCollapsed(!isModelSettingsCollapsed)}
|
539 |
+
disabled={enabledProviders.length === 0}
|
540 |
+
>
|
541 |
+
<div className={`i-ph:caret-${isModelSettingsCollapsed ? 'right' : 'down'} text-lg`} />
|
542 |
+
{isModelSettingsCollapsed ? <span className="text-xs">{model}</span> : <span />}
|
543 |
+
</IconButton>
|
544 |
</div>
|
545 |
{input.length > 3 ? (
|
546 |
<div className="text-xs text-bolt-elements-textTertiary">
|
app/components/chat/SendButton.client.tsx
CHANGED
@@ -3,25 +3,29 @@ import { AnimatePresence, cubicBezier, motion } from 'framer-motion';
|
|
3 |
interface SendButtonProps {
|
4 |
show: boolean;
|
5 |
isStreaming?: boolean;
|
|
|
6 |
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
7 |
onImagesSelected?: (images: File[]) => void;
|
8 |
}
|
9 |
|
10 |
const customEasingFn = cubicBezier(0.4, 0, 0.2, 1);
|
11 |
|
12 |
-
export const SendButton = ({ show, isStreaming, onClick }: SendButtonProps) => {
|
13 |
return (
|
14 |
<AnimatePresence>
|
15 |
{show ? (
|
16 |
<motion.button
|
17 |
-
className="absolute flex justify-center items-center top-[18px] right-[22px] p-1 bg-accent-500 hover:brightness-94 color-white rounded-md w-[34px] h-[34px] transition-theme"
|
18 |
transition={{ ease: customEasingFn, duration: 0.17 }}
|
19 |
initial={{ opacity: 0, y: 10 }}
|
20 |
animate={{ opacity: 1, y: 0 }}
|
21 |
exit={{ opacity: 0, y: 10 }}
|
|
|
22 |
onClick={(event) => {
|
23 |
event.preventDefault();
|
24 |
-
|
|
|
|
|
25 |
}}
|
26 |
>
|
27 |
<div className="text-lg">
|
|
|
3 |
interface SendButtonProps {
|
4 |
show: boolean;
|
5 |
isStreaming?: boolean;
|
6 |
+
disabled?: boolean;
|
7 |
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
8 |
onImagesSelected?: (images: File[]) => void;
|
9 |
}
|
10 |
|
11 |
const customEasingFn = cubicBezier(0.4, 0, 0.2, 1);
|
12 |
|
13 |
+
export const SendButton = ({ show, isStreaming, disabled, onClick }: SendButtonProps) => {
|
14 |
return (
|
15 |
<AnimatePresence>
|
16 |
{show ? (
|
17 |
<motion.button
|
18 |
+
className="absolute flex justify-center items-center top-[18px] right-[22px] p-1 bg-accent-500 hover:brightness-94 color-white rounded-md w-[34px] h-[34px] transition-theme disabled:opacity-50 disabled:cursor-not-allowed"
|
19 |
transition={{ ease: customEasingFn, duration: 0.17 }}
|
20 |
initial={{ opacity: 0, y: 10 }}
|
21 |
animate={{ opacity: 1, y: 0 }}
|
22 |
exit={{ opacity: 0, y: 10 }}
|
23 |
+
disabled={disabled}
|
24 |
onClick={(event) => {
|
25 |
event.preventDefault();
|
26 |
+
if (!disabled) {
|
27 |
+
onClick?.(event);
|
28 |
+
}
|
29 |
}}
|
30 |
>
|
31 |
<div className="text-lg">
|