diff --git a/frontend/src/components/LanguageSelector/LanguageSelector.tsx b/frontend/src/components/LanguageSelector/LanguageSelector.tsx index 4d44eeb..5dc60a5 100644 --- a/frontend/src/components/LanguageSelector/LanguageSelector.tsx +++ b/frontend/src/components/LanguageSelector/LanguageSelector.tsx @@ -1,6 +1,8 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' import { CheckIcon, XMarkIcon } from '@heroicons/react/24/outline' import { LanguageInfo } from '../../services/api' +import { useTheme } from '@mui/material/styles' +import { Box, Typography, Chip, Button, Paper, Divider, Popper, ClickAwayListener } from '@mui/material' interface LanguageSelectorProps { selectedLanguages: string[] @@ -49,8 +51,10 @@ function LanguageSelector({ showPrimarySelector = true, className = '', }: LanguageSelectorProps) { + const theme = useTheme() const [availableLanguages, setAvailableLanguages] = useState(COMMON_LANGUAGES) const [isOpen, setIsOpen] = useState(false) + const anchorRef = useRef(null) // Auto-set primary language to first selected if not specified const effectivePrimary = primaryLanguage || selectedLanguages[0] || '' @@ -94,78 +98,149 @@ function LanguageSelector({ handleLanguageToggle(languageCode) } + const handleClose = () => { + setIsOpen(false) + } + const getLanguageName = (code: string) => { const language = availableLanguages.find(lang => lang.code === code) return language?.name || code } return ( -
+ {/* Selected Languages Display */} -
- + {selectedLanguages.length > 0 ? ( -
+ {selectedLanguages.map((langCode) => ( - - {getLanguageName(langCode)} - {langCode === effectivePrimary && ( - (Primary) - )} - {!disabled && ( - - )} - + label={ + + {getLanguageName(langCode)} + {langCode === effectivePrimary && ( + + (Primary) + + )} + + } + variant={langCode === effectivePrimary ? 'filled' : 'outlined'} + color={langCode === effectivePrimary ? 'primary' : 'default'} + size="small" + onDelete={!disabled ? () => removeLanguage(langCode) : undefined} + deleteIcon={} + sx={{ + '& .MuiChip-deleteIcon': { + color: 'text.secondary', + '&:hover': { + color: 'text.primary', + }, + }, + }} + /> ))} -
+ ) : ( -
+ No languages selected. Documents will use default OCR language. -
+ )} -
+
{/* Language Selector Button */} {!disabled && ( - + {selectedLanguages.length === 0 + ? 'Select OCR languages...' + : `Add more languages (${maxLanguages - selectedLanguages.length} remaining)` + } + )} {/* Dropdown Panel */} - {isOpen && !disabled && ( -
-
-
+ + + + + Available Languages -
+ -
+ {availableLanguages .filter(lang => lang.installed) .map((language) => { @@ -174,91 +249,173 @@ function LanguageSelector({ const canSelect = !isSelected && selectedLanguages.length < maxLanguages return ( -
theme.palette.mode === 'dark' + ? 'rgba(144, 202, 249, 0.16)' + : 'rgba(25, 118, 210, 0.08)' + : 'transparent', + cursor: canSelect || isSelected ? 'pointer' : 'not-allowed', + opacity: !canSelect && !isSelected ? 0.5 : 1, + transition: 'all 0.2s ease-in-out', + '&:hover': canSelect ? { + backgroundColor: (theme) => theme.palette.mode === 'dark' + ? 'rgba(255, 255, 255, 0.05)' + : 'rgba(0, 0, 0, 0.04)', + transform: 'translateY(-1px)', + } : {}, + }} > -
- -
+ + + {language.name} + + {isPrimary && ( + + )} + {/* Primary selector */} {isSelected && showPrimarySelector && selectedLanguages.length > 1 && ( - + )} -
+
) })} -
+ {selectedLanguages.length >= maxLanguages && ( -
- Maximum {maxLanguages} languages allowed for optimal performance. -
+ theme.palette.mode === 'dark' + ? 'rgba(255, 193, 7, 0.1)' + : 'rgba(255, 193, 7, 0.08)', + border: '1px solid', + borderColor: (theme) => theme.palette.mode === 'dark' + ? 'rgba(255, 193, 7, 0.3)' + : 'rgba(255, 193, 7, 0.3)', + borderRadius: 2, + }}> + theme.palette.mode === 'dark' + ? '#ffb74d' + : '#e65100', + fontWeight: 500, + }}> + Maximum {maxLanguages} languages allowed for optimal performance. + + )} -
+ -
- -
-
- )} + + + + + {/* Help Text */} {selectedLanguages.length > 1 && ( -
-

+ + Primary language is processed first for better accuracy. Multiple languages help with mixed-language documents. -

-
+ + )} -
+ ) }