mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 01:10:14 +01:00
🎛️ fix: Improve Frontend Practices for Audio Settings (#3624)
* refactor: do not call await inside useCallbacks, rely on updates for dropdown * fix: remember last selected voice * refactor: Update Speech component to use TypeScript in useCallback * refactor: Update Dropdown component styles to match header theme
This commit is contained in:
parent
8cbb6ba166
commit
05696233a9
20 changed files with 436 additions and 367 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, useContext, useState } from 'react';
|
||||
import React, { FC, useState } from 'react';
|
||||
import {
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
|
|
@ -7,18 +7,14 @@ import {
|
|||
Transition,
|
||||
} from '@headlessui/react';
|
||||
import { AnchorPropsWithSelection } from '@headlessui/react/dist/internal/floating';
|
||||
import type { Option } from '~/common';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
type OptionType = {
|
||||
value: string;
|
||||
display?: string;
|
||||
};
|
||||
|
||||
interface DropdownProps {
|
||||
value: string;
|
||||
label?: string;
|
||||
onChange: (value: string) => void;
|
||||
options: (string | OptionType)[];
|
||||
options: string[] | Option[];
|
||||
className?: string;
|
||||
anchor?: AnchorPropsWithSelection;
|
||||
sizeClasses?: string;
|
||||
|
|
@ -50,8 +46,7 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
<ListboxButton
|
||||
data-testid={testId}
|
||||
className={cn(
|
||||
'relative inline-flex items-center justify-between rounded-md border-gray-50 bg-white py-2 pl-3 pr-8 text-black transition-all duration-100 ease-in-out hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 dark:focus:ring-white dark:focus:ring-offset-gray-700',
|
||||
'w-auto',
|
||||
'focus:ring-offset-ring-offset relative inline-flex w-auto items-center justify-between rounded-md border-border-light bg-header-primary py-2 pl-3 pr-8 text-text-primary transition-all duration-100 ease-in-out hover:bg-header-hover focus:ring-ring-primary',
|
||||
className,
|
||||
)}
|
||||
aria-label="Select an option"
|
||||
|
|
@ -59,8 +54,8 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
<span className="block truncate">
|
||||
{label}
|
||||
{options
|
||||
.map((o) => (typeof o === 'string' ? { value: o, display: o } : o))
|
||||
.find((o) => o.value === selectedValue)?.display || selectedValue}
|
||||
.map((o) => (typeof o === 'string' ? { value: o, label: o } : o))
|
||||
.find((o) => o.value === selectedValue)?.label ?? selectedValue}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<svg
|
||||
|
|
@ -69,7 +64,7 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
className="h-4 w-5 rotate-0 transform text-black transition-transform duration-300 ease-in-out dark:text-gray-50"
|
||||
className="h-4 w-5 rotate-0 transform text-text-primary transition-transform duration-300 ease-in-out"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
|
|
@ -82,7 +77,7 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
>
|
||||
<ListboxOptions
|
||||
className={cn(
|
||||
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-gray-300 bg-white bg-white p-1.5 text-gray-700 shadow-lg transition-opacity focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white',
|
||||
'absolute z-50 mt-1 flex flex-col items-start gap-1 overflow-auto rounded-lg border border-border-medium bg-header-primary p-1.5 shadow-lg transition-opacity',
|
||||
sizeClasses,
|
||||
className,
|
||||
)}
|
||||
|
|
@ -93,15 +88,13 @@ const Dropdown: FC<DropdownProps> = ({
|
|||
<ListboxOption
|
||||
key={index}
|
||||
value={typeof item === 'string' ? item : item.value}
|
||||
className={cn(
|
||||
'relative cursor-pointer select-none rounded border-gray-300 bg-white py-2.5 pl-3 pr-3 text-sm text-gray-700 hover:bg-gray-100 dark:border-gray-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600',
|
||||
)}
|
||||
className="focus-visible:ring-offset ring-offset-ring-offset relative cursor-pointer select-none rounded border-border-light bg-header-primary py-2.5 pl-3 pr-3 text-sm text-text-secondary ring-ring-primary hover:bg-header-hover focus-visible:ring"
|
||||
style={{ width: '100%' }}
|
||||
data-theme={typeof item === 'string' ? item : (item as OptionType).value}
|
||||
data-theme={typeof item === 'string' ? item : (item as Option).value}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<span className="block truncate">
|
||||
{typeof item === 'string' ? item : (item as OptionType).display}
|
||||
{typeof item === 'string' ? item : (item as Option).label}
|
||||
</span>
|
||||
{selectedValue === (typeof item === 'string' ? item : item.value) && (
|
||||
<span className="ml-auto pl-2">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue