@@ -31,10 +31,12 @@ import {
3131 Wrench ,
3232 Share2 ,
3333 ScanSearch , // Added Icon
34- Star
34+ Star ,
35+ Clock
3536} from 'lucide-react' ;
3637import type { RepresentationType , ColoringType , ChainInfo , CustomColorRule , Snapshot , Movie , ColorPalette , PDBMetadata } from '../types' ;
3738import type { DataSource } from '../utils/pdbUtils' ;
39+ import type { HistoryItem } from '../hooks/useHistory' ;
3840import { formatChemicalId } from '../utils/pdbUtils' ;
3941import { findMotifs } from '../utils/searchUtils' ;
4042import type { MotifMatch } from '../utils/searchUtils' ;
@@ -323,6 +325,9 @@ interface ControlsProps {
323325 setShowIons ?: ( show : boolean ) => void ;
324326 onStartTour ?: ( ) => void ;
325327
328+ // History
329+ history ?: HistoryItem [ ] ;
330+
326331 // UI State Lifted Info
327332 openSections ?: Record < string , boolean > ;
328333 onToggleSection ?: ( section : string ) => void ;
@@ -405,12 +410,14 @@ export const Controls: React.FC<ControlsProps> = ({
405410 onToggleMobileSidebar,
406411 onToggleFavorite,
407412 isFavorite,
408- onOpenFavorites
413+ onOpenFavorites,
414+ history = [ ]
409415} ) => {
410416 // Motif Search State
411417 const [ searchPattern , setSearchPattern ] = useState ( '' ) ;
412418 const [ searchResults , setSearchResults ] = useState < MotifMatch [ ] > ( [ ] ) ;
413419 const [ isSearching , setIsSearching ] = useState ( false ) ;
420+ const [ isSearchFocused , setIsSearchFocused ] = useState ( false ) ;
414421
415422
416423 const handleSearch = ( ) => {
@@ -688,12 +695,42 @@ export const Controls: React.FC<ControlsProps> = ({
688695 type = "text"
689696 value = { localPdbId }
690697 onChange = { ( e ) => setLocalPdbId ( e . target . value ) }
698+ onFocus = { ( ) => setIsSearchFocused ( true ) }
699+ onBlur = { ( ) => setTimeout ( ( ) => setIsSearchFocused ( false ) , 200 ) }
691700 placeholder = {
692701 dataSource === 'pubchem' ? "Search PubChem CID (e.g. 2244)" :
693702 "Search PDB ID (e.g. 1crn)"
694703 }
695704 className = { `w-full rounded-lg pl-9 pr-3 py-2 border outline-none transition-all ${ inputBg } ` }
696705 />
706+ { isSearchFocused && history && history . length > 0 && ! localPdbId && (
707+ < div className = "absolute top-full left-0 right-0 mt-2 bg-white dark:bg-neutral-800 rounded-lg shadow-xl border border-neutral-200 dark:border-neutral-700 z-50 overflow-hidden" >
708+ < div className = "px-3 py-2 text-xs font-semibold text-neutral-500 uppercase tracking-wider bg-neutral-50 dark:bg-neutral-900 border-b border-neutral-200 dark:border-neutral-700 flex items-center gap-2" >
709+ < Clock className = "w-3 h-3" />
710+ Recent History
711+ </ div >
712+ < div className = "max-h-60 overflow-y-auto" >
713+ { history . slice ( 0 , 10 ) . map ( ( item ) => (
714+ < button
715+ key = { `${ item . id } -${ item . dataSource } -${ item . timestamp } ` }
716+ type = "button"
717+ onClick = { ( ) => {
718+ setLocalPdbId ( item . id ) ;
719+ setDataSource ( item . dataSource ) ;
720+ setPdbId ( item . id ) ;
721+ setIsSearchFocused ( false ) ;
722+ } }
723+ className = "w-full text-left px-3 py-2 text-sm hover:bg-neutral-100 dark:hover:bg-neutral-700 flex items-center justify-between group border-b border-neutral-100 dark:border-neutral-800 last:border-0"
724+ >
725+ < span className = "font-mono font-medium" > { item . id } </ span >
726+ < span className = "text-[10px] text-neutral-400 group-hover:text-neutral-500 bg-neutral-100 dark:bg-neutral-900 px-1.5 py-0.5 rounded border border-neutral-200 dark:border-neutral-700" >
727+ { item . dataSource === 'pdb' ? 'PDB' : 'CHEM' }
728+ </ span >
729+ </ button >
730+ ) ) }
731+ </ div >
732+ </ div >
733+ ) }
697734 </ div >
698735 { onToggleFavorite && (
699736 < button
0 commit comments