mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
🎨 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:
parent
52f146dd97
commit
150116eefe
8 changed files with 39 additions and 39 deletions
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue