mirror of https://github.com/laurent22/joplin.git
Desktop: Make global search field wider when it has focus
parent
7b8ee467a0
commit
09f41dd50e
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue