Desktop: Make global search field wider when it has focus

pull/3866/head
Laurent Cozic 2020-09-29 12:31:19 +01:00
parent 7b8ee467a0
commit 09f41dd50e
4 changed files with 89 additions and 18 deletions

View File

@ -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)}`;

View File

@ -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,
};
};

View File

@ -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>
);
}

View File

@ -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>