You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Desktop: Make global search field wider when it has focus
This commit is contained in:
		| @@ -101,6 +101,7 @@ const appDefaultState = Object.assign({}, defaultState, { | ||||
| 	lastEditorScrollPercents: {}, | ||||
| 	devToolsVisible: false, | ||||
| 	visibleDialogs: {}, // empty object if no dialog is visible. Otherwise contains the list of visible dialogs. | ||||
| 	focusedField: null, | ||||
| }); | ||||
|  | ||||
| class Application extends BaseApplication { | ||||
| @@ -292,6 +293,21 @@ class Application extends BaseApplication { | ||||
| 				delete newState.visibleDialogs[state.name]; | ||||
| 				break; | ||||
|  | ||||
| 			case 'FOCUS_SET': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| 				newState.focusedField = action.field; | ||||
| 				break; | ||||
|  | ||||
| 			case 'FOCUS_CLEAR': | ||||
|  | ||||
| 				// A field can only clear its own state | ||||
| 				if (action.field === state.focusedField) { | ||||
| 					newState = Object.assign({}, state); | ||||
| 					newState.focusedField = null; | ||||
| 				} | ||||
| 				break; | ||||
|  | ||||
| 			} | ||||
| 		} catch (error) { | ||||
| 			error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`; | ||||
|   | ||||
| @@ -566,7 +566,7 @@ class MainScreenComponent extends React.Component<any, any> { | ||||
| 			const bodyEditor = this.props.settingEditorCodeView ? 'CodeMirror' : 'TinyMCE'; | ||||
| 			return <NoteEditor key={key} bodyEditor={bodyEditor} />; | ||||
| 		} else if (key === 'noteListControls') { | ||||
| 			return <NoteListControls key={key} />; | ||||
| 			return <NoteListControls key={key} showNewNoteButtons={this.props.focusedField !== 'globalSearch'} />; | ||||
| 		} | ||||
|  | ||||
| 		throw new Error(`Invalid layout component: ${key}`); | ||||
| @@ -650,6 +650,7 @@ const mapStateToProps = (state:any) => { | ||||
| 		customCss: state.customCss, | ||||
| 		editorNoteStatuses: state.editorNoteStatuses, | ||||
| 		hasNotesBeingSaved: stateUtils.hasNotesBeingSaved(state), | ||||
| 		focusedField: state.focusedField, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -6,9 +6,12 @@ import CommandService from 'lib/services/CommandService'; | ||||
| import { runtime as focusSearchRuntime } from './commands/focusSearch'; | ||||
| const styled = require('styled-components').default; | ||||
|  | ||||
| interface Props { | ||||
| 	showNewNoteButtons: boolean, | ||||
| } | ||||
|  | ||||
| const StyledRoot = styled.div` | ||||
| 	width: 100%; | ||||
| 	/*height: 100%;*/ | ||||
| 	display: flex; | ||||
| 	flex-direction: row; | ||||
| 	padding: ${(props:any) => props.theme.mainPadding}px; | ||||
| @@ -19,7 +22,12 @@ const StyledButton = styled(Button)` | ||||
| 	margin-left: 8px; | ||||
| `; | ||||
|  | ||||
| export default function NoteListControls() { | ||||
| const ButtonContainer = styled.div` | ||||
| 	display: flex; | ||||
| 	flex-direction: row; | ||||
| `; | ||||
|  | ||||
| export default function NoteListControls(props:Props) { | ||||
| 	const searchBarRef = useRef(null); | ||||
|  | ||||
| 	useEffect(function() { | ||||
| @@ -38,21 +46,31 @@ export default function NoteListControls() { | ||||
| 		CommandService.instance().execute('newNote'); | ||||
| 	} | ||||
|  | ||||
| 	function renderNewNoteButtons() { | ||||
| 		if (!props.showNewNoteButtons) return null; | ||||
|  | ||||
| 		return ( | ||||
| 			<ButtonContainer> | ||||
| 				<StyledButton | ||||
| 					tooltip={CommandService.instance().title('newTodo')} | ||||
| 					iconName="far fa-check-square" | ||||
| 					level={ButtonLevel.Primary} | ||||
| 					onClick={onNewTodoButtonClick} | ||||
| 				/> | ||||
| 				<StyledButton | ||||
| 					tooltip={CommandService.instance().title('newNote')} | ||||
| 					iconName="icon-note" | ||||
| 					level={ButtonLevel.Primary} | ||||
| 					onClick={onNewNoteButtonClick} | ||||
| 				/> | ||||
| 			</ButtonContainer> | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	return ( | ||||
| 		<StyledRoot> | ||||
| 			<SearchBar inputRef={searchBarRef}/> | ||||
| 			<StyledButton | ||||
| 				tooltip={CommandService.instance().title('newTodo')} | ||||
| 				iconName="far fa-check-square" | ||||
| 				level={ButtonLevel.Primary} | ||||
| 				onClick={onNewTodoButtonClick} | ||||
| 			/> | ||||
| 			<StyledButton | ||||
| 				tooltip={CommandService.instance().title('newNote')} | ||||
| 				iconName="icon-note" | ||||
| 				level={ButtonLevel.Primary} | ||||
| 				onClick={onNewNoteButtonClick} | ||||
| 			/> | ||||
| 			{renderNewNoteButtons()} | ||||
| 		</StyledRoot> | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -10,15 +10,42 @@ const { _ } = require('lib/locale.js'); | ||||
| interface Props { | ||||
| 	inputRef?: any, | ||||
| 	notesParentType: string, | ||||
| 	dispatch?: Function, | ||||
| } | ||||
|  | ||||
| function SearchBar(props:Props) { | ||||
| 	const [query, setQuery] = useState(''); | ||||
| 	const iconName = !query ? CommandService.instance().iconName('search') : 'fa fa-times'; | ||||
|  | ||||
| 	const onChange = (event:any) => { | ||||
| 	function onChange(event:any) { | ||||
| 		setQuery(event.currentTarget.value); | ||||
| 	}; | ||||
| 	} | ||||
|  | ||||
| 	function onFocus() { | ||||
| 		props.dispatch({ | ||||
| 			type: 'FOCUS_SET', | ||||
| 			field: 'globalSearch', | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	function onBlur() { | ||||
| 		// Do it after a delay so that the "Clear" button | ||||
| 		// can be clicked on (otherwise the field loses focus | ||||
| 		// and is resized before the click event has been processed) | ||||
| 		setTimeout(() => { | ||||
| 			props.dispatch({ | ||||
| 				type: 'FOCUS_CLEAR', | ||||
| 				field: 'globalSearch', | ||||
| 			}); | ||||
| 		}, 300); | ||||
| 	} | ||||
|  | ||||
| 	function onKeyDown(event:any) { | ||||
| 		if (event.key === 'Escape') { | ||||
| 			setQuery(''); | ||||
| 			if (document.activeElement) (document.activeElement as any).blur(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	const onSearchButtonClick = useCallback(() => { | ||||
| 		setQuery(''); | ||||
| @@ -34,7 +61,16 @@ function SearchBar(props:Props) { | ||||
|  | ||||
| 	return ( | ||||
| 		<Root> | ||||
| 			<SearchInput ref={props.inputRef} value={query} type="text" placeholder={_('Search...')} onChange={onChange}/> | ||||
| 			<SearchInput | ||||
| 				ref={props.inputRef} | ||||
| 				value={query} | ||||
| 				type="text" | ||||
| 				placeholder={_('Search...')} | ||||
| 				onChange={onChange} | ||||
| 				onFocus={onFocus} | ||||
| 				onBlur={onBlur} | ||||
| 				onKeyDown={onKeyDown} | ||||
| 			/> | ||||
| 			<SearchButton onClick={onSearchButtonClick}> | ||||
| 				<SearchButtonIcon className={iconName}/> | ||||
| 			</SearchButton> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user