🎨 refactor: UI stlye (#4438)

* feat: Refactor ChatForm and StopButton components for improved styling and localization

* feat: Refactor AudioRecorder, ChatForm, AttachFile, and SendButton components for improved styling and layout

* feat: Add RevokeAllKeys component and update styling for buttons and inputs

* feat: Refactor ClearChats component and update ClearConvos functionality for improved clarity and user experience

* feat: Remove ClearConvos component and update related imports and functionality in Avatar and DeleteCacheButton components

* feat: Rename DeleteCacheButton to DeleteCache and update related imports; enhance confirmation message in localization

* feat: Update ChatForm layout for RTL support and improve component structure

* feat: Adjust ChatForm layout for improved RTL support and alignment

* feat: Refactor Bookmark components to use new UI elements and improve styling

* feat: Update FileSearch and ShareAgent components for improved button styling and layout

* feat: Update ChatForm and TextareaHeader styles for improved UI consistency

* feat: Refactor Nav components for improved styling and layout adjustments

* feat: Update button sizes and padding for improved UI consistency across chat components

* feat: Remove ClearChatsButton test file as part of code cleanup
This commit is contained in:
Marco Beretta 2024-10-19 14:30:52 +02:00 committed by GitHub
parent 20fb7f05ae
commit 8f3de7d11f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 471 additions and 564 deletions

View file

@ -80,10 +80,8 @@ export default function AudioRecorder({
onClick={isListening ? handleStopRecording : handleStartRecording}
disabled={disabled}
className={cn(
'absolute flex h-[30px] w-[30px] items-center justify-center rounded-lg p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700',
isRTL
? 'bottom-1.5 left-4 md:bottom-3 md:left-12'
: 'bottom-1.5 right-12 md:bottom-3 md:right-12',
'absolute flex size-[35px] items-center justify-center rounded-full p-1 transition-colors hover:bg-surface-hover',
isRTL ? 'bottom-2 left-2' : 'bottom-2 right-2',
)}
description={localize('com_ui_use_micrphone')}
>

View file

@ -156,7 +156,7 @@ const ChatForm = ({ index = 0 }) => {
/>
)}
<PromptsCommand index={index} textAreaRef={textAreaRef} submitPrompt={submitPrompt} />
<div className="bg-token-main-surface-primary relative flex w-full flex-grow flex-col overflow-hidden rounded-2xl border dark:border-gray-600 dark:text-white [&:has(textarea:focus)]:border-gray-300 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)] dark:[&:has(textarea:focus)]:border-gray-500">
<div className="transitional-all relative flex w-full flex-grow flex-col overflow-hidden rounded-3xl bg-surface-tertiary text-text-primary duration-200">
<TextareaHeader addedConvo={addedConvo} setAddedConvo={setAddedConvo} />
<FileFormWrapper disableInputs={disableInputs}>
{endpoint && (
@ -181,7 +181,7 @@ const ChatForm = ({ index = 0 }) => {
endpointSupportsFiles && !isUploadDisabled
? 'pl-10 md:pl-[55px]'
: 'pl-3 md:pl-4',
'm-0 w-full resize-none border-0 bg-transparent py-[10px] placeholder-black/50 focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder-white/50 md:py-3.5 ',
'md:py-3.5- m-0 w-full resize-none bg-surface-tertiary py-[13px] placeholder-black/50 dark:placeholder-white/50 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
SpeechToText && !isRTL ? 'pr-20 md:pr-[85px]' : 'pr-10 md:pr-12',
'max-h-[65vh] md:max-h-[75vh]',
removeFocusRings,
@ -189,22 +189,6 @@ const ChatForm = ({ index = 0 }) => {
/>
)}
</FileFormWrapper>
{(isSubmitting || isSubmittingAdded) && (showStopButton || showStopAdded) ? (
<StopButton
stop={handleStopGenerating}
setShowStopButton={setShowStopButton}
isRTL={isRTL}
/>
) : (
endpoint && (
<SendButton
ref={submitButtonRef}
control={methods.control}
isRTL={isRTL}
disabled={!!(filesLoading || isSubmitting || disableInputs)}
/>
)
)}
{SpeechToText && (
<AudioRecorder
disabled={!!disableInputs}
@ -216,6 +200,25 @@ const ChatForm = ({ index = 0 }) => {
)}
{TextToSpeech && automaticPlayback && <StreamAudio index={index} />}
</div>
<div
className={cn(
'mb-[5px] ml-[8px] flex flex-col items-end justify-end',
isRTL && 'order-first mr-[8px]',
)}
style={{ alignSelf: 'flex-end' }}
>
{(isSubmitting || isSubmittingAdded) && (showStopButton || showStopAdded) ? (
<StopButton stop={handleStopGenerating} setShowStopButton={setShowStopButton} />
) : (
endpoint && (
<SendButton
ref={submitButtonRef}
control={methods.control}
disabled={!!(filesLoading || isSubmitting || disableInputs)}
/>
)
)}
</div>
</div>
</div>
</form>

View file

@ -17,29 +17,22 @@ const AttachFile = ({
const isUploadDisabled = disabled ?? false;
return (
<div
className={cn(
'absolute',
isRTL
? 'bottom-2 right-14 md:bottom-3.5 md:right-3'
: 'bottom-2 left-2 md:bottom-3.5 md:left-4',
)}
>
<FileUpload handleFileChange={handleFileChange} className="flex">
<TooltipAnchor
id="audio-recorder"
disabled={isUploadDisabled}
aria-label={localize('com_sidepanel_attach_files')}
className="btn relative text-black focus:outline-none focus:ring-2 focus:ring-border-xheavy focus:ring-opacity-50 dark:text-white"
style={{ padding: 0 }}
description={localize('com_sidepanel_attach_files')}
>
<div className="flex w-full items-center justify-center gap-2">
<AttachmentIcon />
</div>
</TooltipAnchor>
</FileUpload>
</div>
<FileUpload handleFileChange={handleFileChange} className="flex">
<TooltipAnchor
id="audio-recorder"
aria-label={localize('com_sidepanel_attach_files')}
disabled={isUploadDisabled}
className={cn(
'absolute flex size-[35px] items-center justify-center rounded-full p-1 transition-colors hover:bg-surface-hover',
isRTL ? 'bottom-2 right-2' : 'bottom-2 left-2',
)}
description={localize('com_sidepanel_attach_files')}
>
<div className="flex w-full items-center justify-center gap-2">
<AttachmentIcon />
</div>
</TooltipAnchor>
</FileUpload>
);
};

View file

@ -13,19 +13,17 @@ import AttachFile from './AttachFile';
import FileRow from './FileRow';
import store from '~/store';
function FileFormWrapper({ children, disableInputs } : {
function FileFormWrapper({
children,
disableInputs,
}: {
disableInputs: boolean;
children?: React.ReactNode;
}) {
const { handleFileChange, abortUpload } = useFileHandling();
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
const {
files,
setFiles,
conversation,
setFilesLoading,
} = useChatContext();
const { files, setFiles, conversation, setFilesLoading } = useChatContext();
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
select: (data) => mergeFileConfig(data),
});
@ -33,30 +31,30 @@ function FileFormWrapper({ children, disableInputs } : {
const isRTL = chatDirection === 'rtl';
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as EndpointFileConfig | undefined;
const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as
| EndpointFileConfig
| undefined;
const endpointSupportsFiles: boolean = supportsFiles[endpointType ?? _endpoint ?? ''] ?? false;
const isUploadDisabled = (disableInputs || endpointFileConfig?.disabled) ?? false;
return (<>
<FileRow
files={files}
setFiles={setFiles}
abortUpload={abortUpload}
setFilesLoading={setFilesLoading}
isRTL={isRTL}
Wrapper={({ children }) => (
<div className="mx-2 mt-2 flex flex-wrap gap-2 px-2.5 md:pl-0 md:pr-4">
{children}
</div>
return (
<>
<FileRow
files={files}
setFiles={setFiles}
abortUpload={abortUpload}
setFilesLoading={setFilesLoading}
isRTL={isRTL}
Wrapper={({ children }) => (
<div className="mx-2 mt-2 flex flex-wrap gap-2 px-2.5 md:pl-0 md:pr-4">{children}</div>
)}
/>
{children}
{endpointSupportsFiles && !isUploadDisabled && (
<AttachFile isRTL={isRTL} disabled={disableInputs} handleFileChange={handleFileChange} />
)}
/>
{children}
{endpointSupportsFiles && !isUploadDisabled && <AttachFile
isRTL={isRTL}
disabled={disableInputs}
handleFileChange={handleFileChange}
/>}
</>);
</>
);
}
export default memo(FileFormWrapper);
export default memo(FileFormWrapper);

View file

@ -9,46 +9,40 @@ import { cn } from '~/utils';
type SendButtonProps = {
disabled: boolean;
control: Control<{ text: string }>;
isRTL: boolean;
};
const SubmitButton = React.memo(
forwardRef(
(props: { disabled: boolean; isRTL: boolean }, ref: React.ForwardedRef<HTMLButtonElement>) => {
const localize = useLocalize();
return (
<TooltipAnchor
description={localize('com_nav_send_message')}
render={
<button
ref={ref}
aria-label={localize('com_nav_send_message')}
id="send-button"
disabled={props.disabled}
className={cn(
'absolute rounded-lg border border-black p-0.5 text-white outline-offset-4 transition-colors enabled:bg-black disabled:cursor-not-allowed disabled:bg-black disabled:text-gray-400 disabled:opacity-10 dark:border-white dark:bg-white dark:disabled:bg-white',
props.isRTL
? 'bottom-1.5 left-2 md:bottom-3 md:left-3'
: 'bottom-1.5 right-2 md:bottom-3 md:right-3',
)}
data-testid="send-button"
type="submit"
>
<span className="" data-state="closed">
<SendIcon size={24} />
</span>
</button>
}
></TooltipAnchor>
);
},
),
forwardRef((props: { disabled: boolean }, ref: React.ForwardedRef<HTMLButtonElement>) => {
const localize = useLocalize();
return (
<TooltipAnchor
description={localize('com_nav_send_message')}
render={
<button
ref={ref}
aria-label={localize('com_nav_send_message')}
id="send-button"
disabled={props.disabled}
className={cn(
'rounded-full bg-text-primary p-2 text-text-primary outline-offset-4 transition-all duration-200 disabled:cursor-not-allowed disabled:text-text-secondary disabled:opacity-10',
)}
data-testid="send-button"
type="submit"
>
<span className="" data-state="closed">
<SendIcon size={24} />
</span>
</button>
}
></TooltipAnchor>
);
}),
);
const SendButton = React.memo(
forwardRef((props: SendButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
const data = useWatch({ control: props.control });
return <SubmitButton ref={ref} disabled={props.disabled || !data.text} isRTL={props.isRTL} />;
return <SubmitButton ref={ref} disabled={props.disabled || !data.text} />;
}),
);

View file

@ -1,36 +1,37 @@
import { TooltipAnchor } from '~/components/ui';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
export default function StopButton({ stop, setShowStopButton, isRTL }) {
export default function StopButton({ stop, setShowStopButton }) {
const localize = useLocalize();
return (
<div
className={cn(
'absolute',
isRTL ? 'bottom-3 left-2 md:bottom-4 md:left-4' : 'bottom-3 right-2 md:bottom-4 md:right-4',
)}
>
<button
type="button"
className="border-gizmo-gray-900 rounded-full border-2 p-1 dark:border-gray-200"
aria-label="Stop generating"
onClick={(e) => {
setShowStopButton(false);
stop(e);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
className="text-gizmo-gray-900 h-2 w-2 dark:text-gray-200"
height="16"
width="16"
<TooltipAnchor
description={localize('com_nav_stop_generating')}
render={
<button
type="button"
className={cn(
'rounded-full bg-text-primary p-1.5 text-text-primary outline-offset-4 transition-all duration-200 disabled:cursor-not-allowed disabled:text-text-secondary disabled:opacity-10',
)}
aria-label={localize('com_nav_stop_generating')}
onClick={(e) => {
setShowStopButton(false);
stop(e);
}}
>
<path
d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2z"
strokeWidth="0"
></path>
</svg>
</button>
</div>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="icon-lg text-surface-primary"
>
<rect x="7" y="7" width="10" height="10" rx="1.25" fill="currentColor"></rect>
</svg>
</button>
}
></TooltipAnchor>
);
}

View file

@ -13,7 +13,7 @@ export default function TextareaHeader({
return null;
}
return (
<div className="divide-token-border-light m-1.5 flex flex-col divide-y overflow-hidden rounded-b-lg rounded-t-2xl bg-surface-primary-contrast">
<div className="divide-token-border-light m-1.5 flex flex-col divide-y overflow-hidden rounded-b-lg rounded-t-2xl bg-surface-secondary-alt">
<AddedConvo addedConvo={addedConvo} setAddedConvo={setAddedConvo} />
</div>
);