🎨 style: standardize dropdown styling & fix z-Index layering (#6939)

* fix: Dropdown settings

* refactor: classname cleanup

* refactor: export modal

* fix: Export dropdown
This commit is contained in:
Marco Beretta 2025-04-18 17:36:59 +02:00 committed by GitHub
parent 52f146dd97
commit 150116eefe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 39 additions and 39 deletions

View file

@ -29,7 +29,7 @@ export function BrowserVoiceDropdown() {
onChange={handleVoiceChange} onChange={handleVoiceChange}
sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]" sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]"
testId="BrowserVoiceDropdown" testId="BrowserVoiceDropdown"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );
@ -58,7 +58,7 @@ export function ExternalVoiceDropdown() {
onChange={handleVoiceChange} onChange={handleVoiceChange}
sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]" sizeClasses="min-w-[200px] !max-w-[400px] [--anchor-max-width:400px]"
testId="ExternalVoiceDropdown" testId="ExternalVoiceDropdown"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );

View file

@ -1,10 +1,18 @@
import filenamify from 'filenamify'; import filenamify from 'filenamify';
import { useEffect, useState } from 'react'; import { useEffect, useState, useMemo, useCallback } from 'react';
import type { TConversation } from 'librechat-data-provider'; import type { TConversation } from 'librechat-data-provider';
import { OGDialog, Button, Input, Label, Checkbox, Dropdown } from '~/components/ui'; import { OGDialog, Button, Input, Label, Checkbox, Dropdown } from '~/components/ui';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useLocalize, useExportConversation } from '~/hooks'; import { useLocalize, useExportConversation } from '~/hooks';
const TYPE_OPTIONS = [
{ value: 'screenshot', label: 'screenshot (.png)' },
{ value: 'text', label: 'text (.txt)' },
{ value: 'markdown', label: 'markdown (.md)' },
{ value: 'json', label: 'json (.json)' },
{ value: 'csv', label: 'csv (.csv)' },
];
export default function ExportModal({ export default function ExportModal({
open, open,
onOpenChange, onOpenChange,
@ -21,20 +29,12 @@ export default function ExportModal({
const localize = useLocalize(); const localize = useLocalize();
const [filename, setFileName] = useState(''); const [filename, setFileName] = useState('');
const [type, setType] = useState('Select a file type'); const [type, setType] = useState<string>('screenshot');
const [includeOptions, setIncludeOptions] = useState<boolean | 'indeterminate'>(true); const [includeOptions, setIncludeOptions] = useState<boolean | 'indeterminate'>(true);
const [exportBranches, setExportBranches] = useState<boolean | 'indeterminate'>(false); const [exportBranches, setExportBranches] = useState<boolean | 'indeterminate'>(false);
const [recursive, setRecursive] = useState<boolean | 'indeterminate'>(true); const [recursive, setRecursive] = useState<boolean | 'indeterminate'>(true);
const typeOptions = [
{ value: 'screenshot', label: 'screenshot (.png)' },
{ value: 'text', label: 'text (.txt)' },
{ value: 'markdown', label: 'markdown (.md)' },
{ value: 'json', label: 'json (.json)' },
{ value: 'csv', label: 'csv (.csv)' },
];
useEffect(() => { useEffect(() => {
if (!open && triggerRef && triggerRef.current) { if (!open && triggerRef && triggerRef.current) {
triggerRef.current.focus(); triggerRef.current.focus();
@ -49,17 +49,19 @@ export default function ExportModal({
setRecursive(true); setRecursive(true);
}, [conversation?.title, open]); }, [conversation?.title, open]);
const _setType = (newType: string) => { const handleTypeChange = useCallback((newType: string) => {
const exportBranchesSupport = newType === 'json' || newType === 'csv' || newType === 'webpage'; const branches = newType === 'json' || newType === 'csv' || newType === 'webpage';
const exportOptionsSupport = newType !== 'csv' && newType !== 'screenshot'; const options = newType !== 'csv' && newType !== 'screenshot';
setExportBranches(branches);
setExportBranches(exportBranchesSupport); setIncludeOptions(options);
setIncludeOptions(exportOptionsSupport);
setType(newType); setType(newType);
}; }, []);
const exportBranchesSupport = type === 'json' || type === 'csv' || type === 'webpage'; const exportBranchesSupport = useMemo(
const exportOptionsSupport = type !== 'csv' && type !== 'screenshot'; () => type === 'json' || type === 'csv' || type === 'webpage',
[type],
);
const exportOptionsSupport = useMemo(() => type !== 'csv' && type !== 'screenshot', [type]);
const { exportConversation } = useExportConversation({ const { exportConversation } = useExportConversation({
conversation, conversation,
@ -94,7 +96,13 @@ export default function ExportModal({
<Label htmlFor="type" className="text-left text-sm font-medium"> <Label htmlFor="type" className="text-left text-sm font-medium">
{localize('com_nav_export_type')} {localize('com_nav_export_type')}
</Label> </Label>
<Dropdown value={type} onChange={_setType} options={typeOptions} portal={false} /> <Dropdown
value={type}
onChange={handleTypeChange}
options={TYPE_OPTIONS}
className="z-50"
portal={false}
/>
</div> </div>
</div> </div>
<div className="grid w-full gap-6 sm:grid-cols-2"> <div className="grid w-full gap-6 sm:grid-cols-2">
@ -108,7 +116,6 @@ export default function ExportModal({
id="includeOptions" id="includeOptions"
disabled={!exportOptionsSupport} disabled={!exportOptionsSupport}
checked={includeOptions} checked={includeOptions}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setIncludeOptions} onCheckedChange={setIncludeOptions}
/> />
<label <label
@ -131,7 +138,6 @@ export default function ExportModal({
id="exportBranches" id="exportBranches"
disabled={!exportBranchesSupport} disabled={!exportBranchesSupport}
checked={exportBranches} checked={exportBranches}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setExportBranches} onCheckedChange={setExportBranches}
/> />
<label <label
@ -150,12 +156,7 @@ export default function ExportModal({
{localize('com_nav_export_recursive_or_sequential')} {localize('com_nav_export_recursive_or_sequential')}
</Label> </Label>
<div className="flex h-[40px] w-full items-center space-x-3"> <div className="flex h-[40px] w-full items-center space-x-3">
<Checkbox <Checkbox id="recursive" checked={recursive} onCheckedChange={setRecursive} />
id="recursive"
checked={recursive}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setRecursive}
/>
<label <label
htmlFor="recursive" htmlFor="recursive"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"

View file

@ -30,7 +30,7 @@ export default function FontSizeSelector() {
onChange={handleChange} onChange={handleChange}
testId="font-size-selector" testId="font-size-selector"
sizeClasses="w-[150px]" sizeClasses="w-[150px]"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );

View file

@ -59,7 +59,7 @@ export const ThemeSelector = ({
options={themeOptions} options={themeOptions}
sizeClasses="w-[180px]" sizeClasses="w-[180px]"
testId="theme-selector" testId="theme-selector"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );
@ -113,7 +113,7 @@ export const LangSelector = ({
onChange={onChange} onChange={onChange}
sizeClasses="[--anchor-max-height:256px]" sizeClasses="[--anchor-max-height:256px]"
options={languageOptions} options={languageOptions}
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );

View file

@ -32,7 +32,7 @@ const EngineSTTDropdown: React.FC<EngineSTTDropdownProps> = ({ external }) => {
options={endpointOptions} options={endpointOptions}
sizeClasses="w-[180px]" sizeClasses="w-[180px]"
testId="EngineSTTDropdown" testId="EngineSTTDropdown"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );

View file

@ -31,9 +31,8 @@ const EngineTTSDropdown: React.FC<EngineTTSDropdownProps> = ({ external }) => {
onChange={handleSelect} onChange={handleSelect}
options={endpointOptions} options={endpointOptions}
sizeClasses="w-[180px]" sizeClasses="w-[180px]"
anchor="bottom start"
testId="EngineTTSDropdown" testId="EngineTTSDropdown"
className="rounded-xl" className="z-50"
/> />
</div> </div>
); );

View file

@ -70,7 +70,7 @@ const Dropdown: React.FC<DropdownProps> = ({
<Select.Select <Select.Select
store={selectProps} store={selectProps}
className={cn( className={cn(
'focus:ring-offset-ring-offset relative inline-flex items-center justify-between rounded-lg border border-input bg-background px-3 py-2 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground focus:ring-ring-primary', 'focus:ring-offset-ring-offset relative inline-flex items-center justify-between rounded-xl border border-input bg-background px-3 py-2 text-sm text-text-primary transition-all duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground focus:ring-ring-primary',
iconOnly ? 'h-full w-10' : 'w-fit gap-2', iconOnly ? 'h-full w-10' : 'w-fit gap-2',
className, className,
)} )}

View file

@ -2518,7 +2518,7 @@ html {
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-color: var(--border-light); border-color: var(--border-light);
background-color: hsl(var(--background)); background-color: var(--surface-primary);
padding: 0.5rem; padding: 0.5rem;
color: var(--text-primary); color: var(--text-primary);
box-shadow: box-shadow:
@ -2542,7 +2542,7 @@ html {
} }
.popover-ui:where(.dark, .dark *) { .popover-ui:where(.dark, .dark *) {
background-color: hsl(var(--secondary)); background-color: var(--surface-secondary);
color: var(--text-secondary); color: var(--text-secondary);
box-shadow: box-shadow:
0 10px 15px -3px rgb(0 0 0 / 0.25), 0 10px 15px -3px rgb(0 0 0 / 0.25),