From 382f91c1abb46cc574322a60ed675f5645d7ac0f Mon Sep 17 00:00:00 2001 From: Lorenzo Mattei Date: Mon, 20 Apr 2020 08:04:26 +0200 Subject: [PATCH 1/9] Bump version to 1.16.0-beta1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 802498a29..641de02c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "simplenote", - "version": "1.15.1", + "version": "1.16.0-beta1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 14eaec8f9..542da40db 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "email": "support@simplenote.com" }, "productName": "Simplenote", - "version": "1.15.1", + "version": "1.16.0-beta1", "main": "desktop/index.js", "license": "GPL-2.0", "homepage": "https://simplenote.com", From be9bc653c8890491fea4a91717d40df2689e3490 Mon Sep 17 00:00:00 2001 From: Kat Hagan Date: Thu, 23 Apr 2020 09:30:16 -0700 Subject: [PATCH 2/9] 1.16 release notes (#2018) * 1.16 release notes * Rename RELEASE-NOTES.txt to RELEASE-NOTES.md In #1576 we renamed `CHANGELOG.md` to `RELEASE-NOTES.txt` and in so doing we broke any integration which attempted to render the contents of the file as Markdown. The file continued to be written as a Markdown document but by renaming the extension we prevented any tools which rely on the extension to detect the type and so valuable tools like GitHub's diff viewer wouldn't show the contents of the file as they were written but instead as if they were plain text. In this patch we're renaming it back to a `.md` extension to reflect the reality of the file that it is indeed Markdown content. In so doing we're fixing the integrations that were broken in #1576. * typo fixes Co-authored-by: Dennis Snell --- .github/PULL_REQUEST_TEMPLATE.md | 4 +- RELEASE-NOTES.txt => RELEASE-NOTES.md | 68 ++++++++++++++++++++------- desktop/config-updater.json | 2 +- 3 files changed, 53 insertions(+), 21 deletions(-) rename RELEASE-NOTES.txt => RELEASE-NOTES.md (89%) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2934627a1..657a9b10b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,5 +8,5 @@ > 3. See error... ### Release -***(Required)*** Add a concise statement to `RELEASE-NOTES.txt` if the changes should be included in release notes. Include details about updating the notes in this section. For example: -`RELEASE-NOTES.txt` was updated with: +***(Required)*** Add a concise statement to `RELEASE-NOTES.md` if the changes should be included in release notes. Include details about updating the notes in this section. For example: +`RELEASE-NOTES.md` was updated with: diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.md similarity index 89% rename from RELEASE-NOTES.txt rename to RELEASE-NOTES.md index adfecb172..2c0d41b29 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.md @@ -1,5 +1,34 @@ # Changelog +## [v1.16.0] + +### Enhancements + +- Added keyboard shortcuts help dialog [#1983](https://github.com/Automattic/simplenote-electron/pull/1983) +- Improve search performance [#1941](https://github.com/Automattic/simplenote-electron/pull/1941), [#1966](https://github.com/Automattic/simplenote-electron/pull/1966), [#1979](https://github.com/Automattic/simplenote-electron/pull/1979), [#1982](https://github.com/Automattic/simplenote-electron/pull/1982) + +### Fixes + +- Highlight all search matches in Markdown previews and in note list [#1987](https://github.com/Automattic/simplenote-electron/pull/1987) +- Fix for blurry fonts on LCD screens [#2003](https://github.com/Automattic/simplenote-electron/pull/2003) + +### Other Changes + +- Renamed RELEASE-NOTES to fix integrations broken by #1576 [#2018](https://github.com/Automattic/simplenote-electron/pull/2018) +- Extensive refactoring to move more code into Redux state: + [#1920](https://github.com/Automattic/simplenote-electron/pull/1920) (tag selection), + [#1928](https://github.com/Automattic/simplenote-electron/pull/1928) (system tag), + [#1971](https://github.com/Automattic/simplenote-electron/pull/1971) (select trash and show all notes), + [#1981](https://github.com/Automattic/simplenote-electron/pull/1981) (dialog renderer), + [#1989](https://github.com/Automattic/simplenote-electron/pull/1989) (previous index), + [#1991](https://github.com/Automattic/simplenote-electron/pull/1991) (tagsLoaded), + [#1995](https://github.com/Automattic/simplenote-electron/pull/1995) (compositeNoteList), + [#1996](https://github.com/Automattic/simplenote-electron/pull/1996) (tag suggestions), + [#1999](https://github.com/Automattic/simplenote-electron/pull/1999) (load tags), + [#2004](https://github.com/Automattic/simplenote-electron/pull/2004) (isElectron and isMac utils), +- Replace custom height cache with one provided by react-virtualized [#1829](https://github.com/Automattic/simplenote-electron/pull/1829) +- Dependencies updated [#1951](https://github.com/Automattic/simplenote-electron/pull/1951), [#1993](https://github.com/Automattic/simplenote-electron/pull/1993) + ## [v1.15.1] ### Other Changes @@ -9,6 +38,7 @@ ## [v1.15.0] ### Enhancements + - Stop erasing the copy buffer if copying empty editor selections [#1847](https://github.com/Automattic/simplenote-electron/pull/1847) - Allow for un-selecting a tag by tab or right arrow [#1853](https://github.com/Automattic/simplenote-electron/pull/1853) @qualitymanifest @@ -50,11 +80,13 @@ ## [v1.14.0] ### Enhancements + - Keep note open when transitioning to small screen in focus mode [#1763](https://github.com/Automattic/simplenote-electron/pull/1763) - Added GenericName (description) field for app on Linux [#1761](https://github.com/Automattic/simplenote-electron/pull/1761) - Allow width attribute on img tags [#1833](https://github.com/Automattic/simplenote-electron/pull/1833) ### Fixes + - Makes settings scrollable on shorter smaller view ports [#1767](https://github.com/Automattic/simplenote-electron/pull/1767) - After selecting a revision to restore ensure that choice is sync'd [#1774](https://github.com/Automattic/simplenote-electron/pull/1774) - Added indication that publish url has been copied [#1743](https://github.com/Automattic/simplenote-electron/pull/1743) @@ -104,9 +136,9 @@ ### Enhancements - - Updated menu icon to use the new icon set [#1694](https://github.com/Automattic/simplenote-electron/pull/1694) - - Added script to deploy web app [#1723](https://github.com/Automattic/simplenote-electron/pull/1723) - - Prioritize search results where title matches query [#1705](https://github.com/Automattic/simplenote-electron/pull/1705) +- Updated menu icon to use the new icon set [#1694](https://github.com/Automattic/simplenote-electron/pull/1694) +- Added script to deploy web app [#1723](https://github.com/Automattic/simplenote-electron/pull/1723) +- Prioritize search results where title matches query [#1705](https://github.com/Automattic/simplenote-electron/pull/1705) ### Fixes @@ -126,7 +158,7 @@ ### Fixes - - Fixed bug that only shows the first line of text in note list preview [#1647](https://github.com/Automattic/simplenote-electron/pull/1647) +- Fixed bug that only shows the first line of text in note list preview [#1647](https://github.com/Automattic/simplenote-electron/pull/1647) ### Other Changes @@ -134,26 +166,26 @@ ### Enhancements - - Add ability to select system as a theme option and make it the default - - Added support for the unicode bullet • in list items - - Display a notice that notes are loading when notes are loading - - In dev mode open Chrome Dev Tools in a separate window +- Add ability to select system as a theme option and make it the default +- Added support for the unicode bullet • in list items +- Display a notice that notes are loading when notes are loading +- In dev mode open Chrome Dev Tools in a separate window ### Fixes - - Rework WordPress.com signin to prevent infinite looping and login failures [#1627](https://github.com/Automattic/simplenote-electron/pull/1627) - - Update link to release-notes in updater config: CHANGELOG -> RELEASE_NOTES - - Stop showing that there are no notes when initially loading notes from the server. [#1680](https://github.com/Automattic/simplenote-electron/pull/1680) +- Rework WordPress.com signin to prevent infinite looping and login failures [#1627](https://github.com/Automattic/simplenote-electron/pull/1627) +- Update link to release-notes in updater config: CHANGELOG -> RELEASE_NOTES +- Stop showing that there are no notes when initially loading notes from the server. [#1680](https://github.com/Automattic/simplenote-electron/pull/1680) - ### Other changes +### Other changes - - Updated dependencies +- Updated dependencies ## [v1.9.1] ### Fixes - - Prevent ulimited duplication of changes after signing out and signing in [#1664](https://github.com/Automattic/simplenote-electron/pull/1664) +- Prevent ulimited duplication of changes after signing out and signing in [#1664](https://github.com/Automattic/simplenote-electron/pull/1664) ## [v1.9.0] @@ -161,8 +193,8 @@ - Open new note automatically upon creation [1582](https://github.com/Automattic/simplenote-electron/pull/1582) - Updated colors to use Color Studio, the color palette for Automattic products - - [#1565](https://github.com/Automattic/simplenote-electron/pull/1565) - - [#1612](https://github.com/Automattic/simplenote-electron/pull/1612) + - [#1565](https://github.com/Automattic/simplenote-electron/pull/1565) + - [#1612](https://github.com/Automattic/simplenote-electron/pull/1612) ### Fixes @@ -170,8 +202,8 @@ - Fixes vertical spacing with nested markdown lists - Fixes sort order on revision slider when the timestamps don't match the change sequence [#1605](https://github.com/Automattic/simplenote-electron/pull/1605) - Prevents note corruption when receiving remote updates when local updates are pending - - [#1598](https://github.com/Automattic/simplenote-electron/pull/1598) - - [#1599](https://github.com/Automattic/simplenote-electron/pull/1599) + - [#1598](https://github.com/Automattic/simplenote-electron/pull/1598) + - [#1599](https://github.com/Automattic/simplenote-electron/pull/1599) ### Other changes diff --git a/desktop/config-updater.json b/desktop/config-updater.json index 1e8b2420d..238ddb4bd 100644 --- a/desktop/config-updater.json +++ b/desktop/config-updater.json @@ -1,7 +1,7 @@ { "updater": { "downloadUrl": "https://github.com/Automattic/simplenote-electron/releases/latest", - "changelogUrl": "https://github.com/Automattic/simplenote-electron/blob/master/RELEASE-NOTES.txt", + "changelogUrl": "https://github.com/Automattic/simplenote-electron/blob/master/RELEASE-NOTES.md", "apiUrl": "https://api.github.com/repos/automattic/simplenote-electron/releases/latest", "delay": 2000, "interval": 600000 From 0dddf4aa3bf075b86bf27f1586908323ecb992f9 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Mon, 27 Apr 2020 19:09:16 -0700 Subject: [PATCH 3/9] =?UTF-8?q?Hotkeys:=20Always=20allow=20using=20the=20C?= =?UTF-8?q?trl-T=20shortcut=20to=20jump=20between=20note/=E2=80=A6=20(#204?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Hotkeys: Always allow using the Ctrl-T shortcut to jump between note/tags Previously we were only allowing a switch _from_ the note editor _to_ the tag editor, or _from_ the tag editor _to_ the note editor, but we really want to allow jumping between these fields any time, even if none is selected. With the work to improve keyboard shortcut usability this is more important since we're emphasizing keyboard navigation. In this patch we change the conditional from one that gates the behavior to one that uses the current focus to determine which to jump to. * Prevent the TagField from stealing focus when swapping to editor --- lib/note-editor/index.tsx | 6 +++--- lib/tag-field/index.tsx | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/note-editor/index.tsx b/lib/note-editor/index.tsx index 21071ff32..cd47646cb 100644 --- a/lib/note-editor/index.tsx +++ b/lib/note-editor/index.tsx @@ -101,13 +101,13 @@ export class NoteEditor extends Component { ) { // prefer focusing the edit field first if (!this.editFieldHasFocus()) { - this.focusNoteEditor && this.focusNoteEditor(); + this.focusNoteEditor?.(); event.stopPropagation(); event.preventDefault(); return false; - } else if (!this.tagFieldHasFocus()) { - this.focusTagField && this.focusTagField(); + } else { + this.focusTagField?.(); event.stopPropagation(); event.preventDefault(); diff --git a/lib/tag-field/index.tsx b/lib/tag-field/index.tsx index b22feb97e..46eaf3fdc 100644 --- a/lib/tag-field/index.tsx +++ b/lib/tag-field/index.tsx @@ -1,6 +1,5 @@ import React, { Component, - KeyboardEvent, KeyboardEventHandler, MouseEvent, RefObject, @@ -76,10 +75,12 @@ export class TagField extends Component { this.props.storeHasFocus(this.hasFocus); document.addEventListener('click', this.unselect, true); + window.addEventListener('keydown', this.preventStealingFocus, true); } componentWillUnmount() { document.removeEventListener('click', this.unselect, true); + window.removeEventListener('keydown', this.preventStealingFocus, true); } componentDidUpdate() { @@ -121,9 +122,7 @@ export class TagField extends Component { this.updateTags(differenceBy(tags, [tagName], s => s.toLocaleLowerCase())); if (selectedTag === tagName) { - this.setState({ selectedTag: '' }, () => { - invoke(this, 'tagInput.focus'); - }); + this.setState({ selectedTag: '' }, () => this.tagInput?.focus()); } analytics.tracks.recordEvent('editor_tag_removed'); @@ -166,6 +165,16 @@ export class TagField extends Component { } }; + preventStealingFocus = ({ ctrlKey, metaKey, code }: KeyboardEvent) => { + const cmdOrCtrl = ctrlKey || metaKey; + + if (cmdOrCtrl && 'KeyT' === code) { + this.setState({ selectedTag: '' }); + } + + return true; + }; + updateTags = tags => this.props.updateNoteTags({ note: this.props.note, tags }); @@ -191,7 +200,7 @@ export class TagField extends Component { setTimeout(() => this.setState({ showEmailTooltip: false }), 5000); }; - onKeyDown = (e: KeyboardEvent) => { + onKeyDown = (e: React.KeyboardEvent) => { if (this.state.showEmailTooltip) { this.hideEmailTooltip(); } @@ -210,7 +219,7 @@ export class TagField extends Component { storeTagInput = (value: string, callback?: (...args: any) => any) => this.setState({ tagInput: value }, callback); - unselect = (event: KeyboardEvent) => { + unselect = (event: React.KeyboardEvent) => { if (!this.state.selectedTag) { return; } From 0a1fde6fb1829f8142edec0a34ed75484f99fc84 Mon Sep 17 00:00:00 2001 From: Kat Hagan Date: Tue, 28 Apr 2020 12:20:02 -0700 Subject: [PATCH 4/9] Fix note list toggle (#2037) * most of a fix for this by not overloading CLOSE_NOTE * default to true so we show the note list on first load on small screens * toggle back into the note list after next/prev * don't open note list on next/prev if it's not already open * change wording of note list key since it's a toggle now * Remove some unused code * Remove toggling behavior from note list * Separate the action of selecting a note from the action of opening it * Disable note-editing from list view and open note on Enter presses It was possible to edit the contents of a note in a small-screen view with the note list open. This was confusing because it wasn't obvious that the edits were applying. In this change the editor (with help of some ugly prop-drilling) disables itself while in a small-screen view while the note list is open. In order to ease the jump back to the note the Enter key now opens it. * review cleanup * Keep highlighted note in view in list view * Stop rendering editor when it's not visible Previously we were always rendering the editor. When very large or slow notes were in the list it made for abrupt pauses while scrolling through the list. In this change we stop rendering the editor altogether if only the list view is visible. This has removed all abrupt pauses when scrolling through the list view on the narrow-screen mode. * Remove workaround for disabling the editor while hidden Co-authored-by: Dennis Snell --- lib/app-layout/index.tsx | 33 +++++++++++++--------- lib/dialogs/keybindings/index.tsx | 2 +- lib/note-content-editor.tsx | 5 +++- lib/note-editor/index.tsx | 14 +++++---- lib/note-list/index.tsx | 47 ++++++++++++++++++++----------- lib/note-toolbar/index.tsx | 10 +++---- lib/state/action-types.ts | 4 +++ lib/state/ui/actions.ts | 9 ++++++ lib/state/ui/reducer.ts | 14 +++++---- 9 files changed, 91 insertions(+), 47 deletions(-) diff --git a/lib/app-layout/index.tsx b/lib/app-layout/index.tsx index 289e2c951..0c07f4592 100644 --- a/lib/app-layout/index.tsx +++ b/lib/app-layout/index.tsx @@ -35,6 +35,7 @@ type OwnProps = { type StateProps = { isNoteOpen: boolean; keyboardShortcutsAreOpen: boolean; + showNoteList: boolean; }; type DispatchProps = { @@ -72,6 +73,7 @@ export class AppLayout extends Component { render = () => { const { + showNoteList, isFocusMode = false, isNavigationOpen, isNoteInfoOpen, @@ -89,6 +91,8 @@ export class AppLayout extends Component { 'is-showing-note-info': isNoteInfoOpen, }); + const editorVisible = !(showNoteList && isSmallScreen); + const placeholder = (
@@ -104,19 +108,21 @@ export class AppLayout extends Component {
-
- - } - /> - -
+ {editorVisible && ( +
+ + } + /> + +
+ )} ); @@ -128,6 +134,7 @@ const mapStateToProps: S.MapState = ({ }) => ({ keyboardShortcutsAreOpen: dialogs.includes('KEYBINDINGS'), isNoteOpen: !showNoteList, + showNoteList, }); const mapDispatchToProps: S.MapDispatch = { diff --git a/lib/dialogs/keybindings/index.tsx b/lib/dialogs/keybindings/index.tsx index 65c2b4f8e..0cf4231e5 100644 --- a/lib/dialogs/keybindings/index.tsx +++ b/lib/dialogs/keybindings/index.tsx @@ -118,7 +118,7 @@ export class AboutDialog extends Component {
  • - Show note list + Toggle note list
    (on narrow screens)
    diff --git a/lib/note-content-editor.tsx b/lib/note-content-editor.tsx index 5be405a0d..7be2c0ff2 100644 --- a/lib/note-content-editor.tsx +++ b/lib/note-content-editor.tsx @@ -39,6 +39,7 @@ const isElectron = (() => { })(); type StateProps = { + editingEnabled: boolean; searchQuery: string; }; @@ -373,7 +374,9 @@ class NoteContentEditor extends Component { } } -const mapStateToProps: S.MapState = ({ ui: { searchQuery } }) => ({ +const mapStateToProps: S.MapState = ({ + ui: { searchQuery, showNoteList }, +}) => ({ searchQuery, }); diff --git a/lib/note-editor/index.tsx b/lib/note-editor/index.tsx index cd47646cb..45ba7f395 100644 --- a/lib/note-editor/index.tsx +++ b/lib/note-editor/index.tsx @@ -6,21 +6,26 @@ import { property } from 'lodash'; import NoteDetail from '../note-detail'; import { toggleEditMode } from '../state/ui/actions'; -import { closeNote, markdownNote } from '../state/ui/actions'; +import { markdownNote, toggleNoteList } from '../state/ui/actions'; import * as S from '../state'; import * as T from '../types'; +type OwnProps = { + isSmallScreen: boolean; +}; + type StateProps = { note: T.NoteEntity | null; }; type DispatchProps = { toggleMarkdown: (note: T.NoteEntity, enableMarkdown: boolean) => any; + toggleNoteList: () => any; toggleEditMode: () => any; }; -type Props = DispatchProps & StateProps; +type Props = OwnProps & DispatchProps & StateProps; export class NoteEditor extends Component { static displayName = 'NoteEditor'; @@ -28,7 +33,6 @@ export class NoteEditor extends Component { static propTypes = { allTags: PropTypes.array.isRequired, isEditorActive: PropTypes.bool.isRequired, - isSmallScreen: PropTypes.bool.isRequired, noteBucket: PropTypes.object.isRequired, fontSize: PropTypes.number, onUpdateContent: PropTypes.func.isRequired, @@ -86,7 +90,7 @@ export class NoteEditor extends Component { // open note list if (this.props.isSmallScreen && cmdOrCtrl && shiftKey && 'KeyL' === code) { - this.props.closeNote(); + this.props.toggleNoteList(); event.stopPropagation(); event.preventDefault(); return false; @@ -184,7 +188,7 @@ const mapStateToProps: S.MapState = ({ }); const mapDispatchToProps: S.MapDispatch = dispatch => ({ - closeNote: () => dispatch(closeNote()), + toggleNoteList: () => dispatch(toggleNoteList()), toggleMarkdown: (note, enableMarkdown) => dispatch(markdownNote(note, enableMarkdown)), toggleEditMode: () => dispatch(toggleEditMode()), diff --git a/lib/note-list/index.tsx b/lib/note-list/index.tsx index be29ebd0b..34d5739f2 100644 --- a/lib/note-list/index.tsx +++ b/lib/note-list/index.tsx @@ -40,6 +40,7 @@ type StateProps = { selectedNote: T.NoteEntity | null; selectedNoteContent: string; selectedNotePreview: { title: string; preview: string }; + showNoteList: boolean; showTrash: boolean; tagResultsFound: number; }; @@ -49,6 +50,7 @@ type DispatchProps = { onEmptyTrash: () => any; onSelectNote: (note: T.NoteEntity | null) => any; onPinNote: (note: T.NoteEntity, shouldPin: boolean) => any; + openNote: (note: T.NoteEntity) => any; }; type Props = Readonly; @@ -74,10 +76,9 @@ const heightCache = new CellMeasurerCache({ * @param notes list of filtered notes * @param searchQuery search searchQuery * @param noteDisplay list view style: comfy, condensed, expanded + * @param openNote used to select a note and open it in the editor * @param selectedNoteId id of currently selected note - * @param onSelectNote used to change the current note selection * @param onPinNote used to pin a note to the top of the list - * @param isSmallScreen whether we're in a narrow view * @returns does the actual rendering for the List */ const renderNote = ( @@ -86,16 +87,14 @@ const renderNote = ( searchQuery, noteDisplay, highlightedIndex, - onSelectNote, onPinNote, - isSmallScreen, + openNote, }: { searchQuery: string; noteDisplay: T.ListDisplayMode; highlightedIndex: number; - onSelectNote: DispatchProps['onSelectNote']; onPinNote: DispatchProps['onPinNote']; - isSmallScreen: boolean; + openNote: DispatchProps['openNote']; } ): ListRowRenderer => ({ index, key, parent, style }) => { const note = notes[index]; @@ -130,7 +129,7 @@ const renderNote = ( const isPinned = note.data.systemTags.includes('pinned'); const isPublished = !!note.data.publishURL; const classes = classNames('note-list-item', { - 'note-list-item-selected': !isSmallScreen && highlightedIndex === index, + 'note-list-item-selected': highlightedIndex === index, 'note-list-item-pinned': isPinned, 'published-note': isPublished, }); @@ -138,8 +137,6 @@ const renderNote = ( const terms = getTerms(searchQuery).map(makeFilterDecorator); const decorators = [checkboxDecorator, ...terms]; - const selectNote = () => onSelectNote(note); - return ( openNote(note)} >
    {decorateWith(decorators, title)} @@ -249,6 +246,7 @@ export class NoteList extends Component { } if (notes.length === 0 && selectedNote) { + // unselect active note if it doesn't match search this.props.closeNote(); this.setState({ selectedIndex: null }); } @@ -300,7 +298,7 @@ export class NoteList extends Component { handleShortcut = (event: KeyboardEvent) => { const { ctrlKey, code, metaKey, shiftKey } = event; - const { notes } = this.props; + const { isSmallScreen, notes, showNoteList } = this.props; const { selectedIndex: index } = this.state; const highlightedIndex = this.getHighlightedIndex(this.props); @@ -332,6 +330,19 @@ export class NoteList extends Component { return false; } + if ( + isSmallScreen && + showNoteList && + code === 'Enter' && + highlightedIndex !== null + ) { + this.props.openNote(notes[highlightedIndex]); + + event.stopPropagation(); + event.preventDefault(); + return false; + } + return true; }; @@ -385,10 +396,9 @@ export class NoteList extends Component { render() { const { hasLoaded, - isSmallScreen, noteDisplay, notes, - onSelectNote, + openNote, onEmptyTrash, onPinNote, searchQuery, @@ -411,9 +421,8 @@ export class NoteList extends Component { searchQuery, highlightedIndex, noteDisplay, - onSelectNote, onPinNote, - isSmallScreen, + openNote, }); const isEmptyList = compositeNoteList.length === 0; @@ -450,12 +459,13 @@ export class NoteList extends Component { rowCount={compositeNoteList.length} rowHeight={heightCache.rowHeight} rowRenderer={renderNoteRow} + scrollToIndex={highlightedIndex} width={width} /> )}
    - {!!showTrash && emptyTrashButton} + {showTrash && emptyTrashButton} )} @@ -463,7 +473,7 @@ export class NoteList extends Component { } } -const { emptyTrash, loadAndSelectNote } = appState.actionCreators; +const { emptyTrash } = appState.actionCreators; const mapStateToProps: S.MapState = ({ appState: state, @@ -472,6 +482,7 @@ const mapStateToProps: S.MapState = ({ note, openedTag, searchQuery, + showNoteList, showTrash, tagSuggestions, }, @@ -508,6 +519,7 @@ const mapStateToProps: S.MapState = ({ selectedNote: note, selectedNotePreview, selectedNoteContent: get(note, 'data.content'), + showNoteList, showTrash, tagResultsFound: tagSuggestions.length, }; @@ -524,6 +536,7 @@ const mapDispatchToProps: S.MapDispatch = ( analytics.tracks.recordEvent('list_note_opened'); }, onPinNote: (note, shouldPin) => dispatch(actions.ui.pinNote(note, shouldPin)), + openNote: (note: T.NoteEntity) => dispatch(actions.ui.openNote(note)), }); export default connect(mapStateToProps, mapDispatchToProps)(NoteList); diff --git a/lib/note-toolbar/index.tsx b/lib/note-toolbar/index.tsx index e06b1cada..a83365d48 100644 --- a/lib/note-toolbar/index.tsx +++ b/lib/note-toolbar/index.tsx @@ -14,9 +14,9 @@ import ShareIcon from '../icons/share'; import SidebarIcon from '../icons/sidebar'; import { - closeNote, toggleEditMode, toggleNoteInfo, + toggleNoteList, toggleRevisions, } from '../state/ui/actions'; @@ -24,9 +24,9 @@ import * as S from '../state'; import * as T from '../types'; type DispatchProps = { - closeNote: () => any; toggleEditMode: () => any; toggleNoteInfo: () => any; + toggleNoteList: () => any; toggleRevisions: () => any; }; @@ -87,7 +87,7 @@ export class NoteToolbar extends Component {
    } - onClick={this.props.closeNote} + onClick={this.props.toggleNoteList} title="Back" />
    @@ -141,7 +141,7 @@ export class NoteToolbar extends Component {
    } - onClick={this.props.closeNote} + onClick={this.props.toggleNoteList} title="Back" />
    @@ -185,9 +185,9 @@ const mapStateToProps: S.MapState = ({ }; const mapDispatchToProps: S.MapDispatch = { - closeNote, toggleEditMode, toggleNoteInfo, + toggleNoteList, toggleRevisions, }; diff --git a/lib/state/action-types.ts b/lib/state/action-types.ts index 2aa9e5b48..5ecb09a46 100644 --- a/lib/state/action-types.ts +++ b/lib/state/action-types.ts @@ -56,6 +56,7 @@ export type FilterNotes = Action< { notes: T.NoteEntity[]; tags: T.TagEntity[] } >; export type FocusSearchField = Action<'FOCUS_SEARCH_FIELD'>; +export type OpenNote = Action<'OPEN_NOTE', { note: T.NoteEntity }>; export type RemoteNoteUpdate = Action< 'REMOTE_NOTE_UPDATE', { noteId: T.EntityId; data: T.Note } @@ -87,6 +88,7 @@ export type TagsLoaded = Action< { tags: T.TagEntity[]; sortTagsAlpha: boolean } >; export type ToggleNavigation = Action<'NAVIGATION_TOGGLE'>; +export type ToggleNoteList = Action<'NOTE_LIST_TOGGLE'>; export type ToggleNoteInfo = Action<'NOTE_INFO_TOGGLE'>; export type ToggleSimperiumConnectionStatus = Action< 'SIMPERIUM_CONNECTION_STATUS_TOGGLE', @@ -112,6 +114,7 @@ export type ActionType = | FilterNotes | FocusSearchField | RemoteNoteUpdate + | OpenNote | OpenTag | RestoreNote | Search @@ -139,6 +142,7 @@ export type ActionType = | TagsLoaded | ToggleEditMode | ToggleNavigation + | ToggleNoteList | ToggleNoteInfo | ToggleRevisions | ToggleSimperiumConnectionStatus diff --git a/lib/state/ui/actions.ts b/lib/state/ui/actions.ts index fe71d0f19..7aea6328d 100644 --- a/lib/state/ui/actions.ts +++ b/lib/state/ui/actions.ts @@ -60,6 +60,11 @@ export const publishNote: A.ActionCreator = ( shouldHaveTag: shoudlPublish, }); +export const openNote: A.ActionCreator = (note: T.NoteEntity) => ({ + type: 'OPEN_NOTE', + note, +}); + export const openTag: A.ActionCreator = (tag: T.TagEntity) => ({ type: 'OPEN_TAG', tag, @@ -135,6 +140,10 @@ export const toggleNavigation: A.ActionCreator = () => ({ type: 'NAVIGATION_TOGGLE', }); +export const toggleNoteList: A.ActionCreator = () => ({ + type: 'NOTE_LIST_TOGGLE', +}); + export const toggleNoteInfo: A.ActionCreator = () => ({ type: 'NOTE_INFO_TOGGLE', }); diff --git a/lib/state/ui/reducer.ts b/lib/state/ui/reducer.ts index 3e4aa2866..dedea7f64 100644 --- a/lib/state/ui/reducer.ts +++ b/lib/state/ui/reducer.ts @@ -39,12 +39,12 @@ const editingTags: A.Reducer = (state = false, action) => { switch (action.type) { case 'TAG_EDITING_TOGGLE': return !state; + case 'OPEN_NOTE': case 'SELECT_NOTE': case 'OPEN_TAG': case 'SELECT_TRASH': case 'SHOW_ALL_NOTES': case 'NAVIGATION_TOGGLE': - case 'App.toggleNoteInfo': return false; default: return state; @@ -80,6 +80,7 @@ const noteRevisions: A.Reducer = ( case 'STORE_REVISIONS': return action.revisions; case 'CREATE_NOTE': + case 'OPEN_NOTE': case 'SELECT_NOTE': return emptyList as T.NoteEntity[]; default: @@ -107,6 +108,7 @@ const selectedRevision: A.Reducer = ( case 'SELECT_REVISION': return action.revision; case 'CREATE_NOTE': + case 'OPEN_NOTE': case 'REVISIONS_TOGGLE': case 'SELECT_NOTE': return null; @@ -115,12 +117,12 @@ const selectedRevision: A.Reducer = ( } }; -const showNoteList: A.Reducer = (state = false, action) => { +const showNoteList: A.Reducer = (state = true, action) => { switch (action.type) { - case 'CLOSE_NOTE': - return true; + case 'NOTE_LIST_TOGGLE': + return !state; - case 'SELECT_NOTE': + case 'OPEN_NOTE': return false; default: @@ -185,6 +187,7 @@ const showRevisions: A.Reducer = (state = false, action) => { switch (action.type) { case 'REVISIONS_TOGGLE': return !state; + case 'OPEN_NOTE': case 'SELECT_NOTE': case 'CREATE_NOTE': return false; @@ -218,6 +221,7 @@ const note: A.Reducer = (state = null, action) => { case 'TRASH_NOTE': case 'OPEN_TAG': return null; + case 'OPEN_NOTE': case 'SELECT_NOTE': return action.options ? { From d49e90d4d2af90487c62311d853b1f3347dc7782 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 28 Apr 2020 15:33:51 -0700 Subject: [PATCH 5/9] Fix keyboard shortcut issues identified in release testing (#2046) * Fix keyboard shortcut issues identified in release testing Resolves #2025 Resolves #2026 Changes: - restores "focus mode" hotkey to Ctrl + Shift + F - resets "focus search field" hotkey to Ctrl + F - rewords description of Ctrl + G - rewords "select previous/next" to "above/below" - disables browser default behavior on Ctrl + G - removes hotkey Ctrl + Backspace to prevent accidentally trashing note - inlines keyboard shortcut explainer to one column only for visual styling purposes * Stop beeping on ctrl + / * Make the delete-key behavior on macOS slightly more clear * Use cmd on web as well as desktop macOS * Web should always be ctrl even on macOS * add tooltip to Back, handle KeyL from note list * Move list-toggle keybinding up to make sure we always capture it * Stop passing up/down note selection hotkeys to parent app * Recompute note list heights when toggling note list Co-authored-by: Jonathan (JB) Belcher Co-authored-by: Kat Hagan --- desktop/menus/view-menu.js | 1 - lib/app-layout/index.tsx | 3 +++ lib/app.tsx | 23 ++++++++++++++----- lib/dialogs/keybindings/index.tsx | 36 ++++++++++++++++++++++-------- lib/dialogs/keybindings/style.scss | 18 +++------------ lib/note-detail/index.tsx | 7 ++++-- lib/note-editor/index.tsx | 8 ------- lib/note-list/index.tsx | 21 +++++++++++++---- lib/note-toolbar/index.tsx | 4 ++-- 9 files changed, 74 insertions(+), 47 deletions(-) diff --git a/desktop/menus/view-menu.js b/desktop/menus/view-menu.js index 2e34e9338..d4c1bdff4 100644 --- a/desktop/menus/view-menu.js +++ b/desktop/menus/view-menu.js @@ -137,7 +137,6 @@ const buildViewMenu = settings => { }, { label: 'Focus Mode', - accelerator: 'CommandOrControl+Shift+F', type: 'checkbox', checked: settings.focusModeEnabled, click: appCommandSender({ action: 'toggleFocusMode' }), diff --git a/lib/app-layout/index.tsx b/lib/app-layout/index.tsx index 0c07f4592..0150a57a9 100644 --- a/lib/app-layout/index.tsx +++ b/lib/app-layout/index.tsx @@ -68,6 +68,9 @@ export class AppLayout extends Component { keyboardShortcutsAreOpen ? hideKeyboardShortcuts() : showKeyboardShortcuts(); + + event.stopPropagation(); + event.preventDefault(); } }; diff --git a/lib/app.tsx b/lib/app.tsx index fb5a3c82e..1d84da11f 100644 --- a/lib/app.tsx +++ b/lib/app.tsx @@ -256,7 +256,7 @@ export const App = connect( return false; } - if (cmdOrCtrl && shiftKey && 'KeyF' === code) { + if (cmdOrCtrl && !shiftKey && 'KeyF' === code) { this.props.focusSearchField(); event.stopPropagation(); @@ -264,6 +264,14 @@ export const App = connect( return false; } + if (cmdOrCtrl && shiftKey && 'KeyF' === code) { + this.props.toggleFocusMode(); + + event.stopPropagation(); + event.preventDefault(); + return false; + } + if (cmdOrCtrl && shiftKey && 'KeyN' === code) { this.props.actions.newNote({ noteBucket: this.props.noteBucket, @@ -275,11 +283,7 @@ export const App = connect( return false; } - if ( - this.props.ui.note && - cmdOrCtrl && - ('Delete' === code || 'Backspace' === code) - ) { + if (this.props.ui.note && cmdOrCtrl && 'Delete' === code) { this.props.actions.trashNote({ noteBucket: this.props.noteBucket, note: this.props.ui.note, @@ -293,6 +297,13 @@ export const App = connect( return false; } + // prevent default browser behavior for search + // will bubble up from note-detail + if (cmdOrCtrl && 'KeyG' === code) { + event.stopPropagation(); + event.preventDefault(); + } + return true; }; diff --git a/lib/dialogs/keybindings/index.tsx b/lib/dialogs/keybindings/index.tsx index 0cf4231e5..1a2e697cb 100644 --- a/lib/dialogs/keybindings/index.tsx +++ b/lib/dialogs/keybindings/index.tsx @@ -46,7 +46,7 @@ const Keys = ({ export class AboutDialog extends Component { render() { const { closeDialog, isElectron, isMacApp } = this.props; - + const isMac = isMacApp || navigator.userAgent.indexOf('Mac OS X'); const CmdOrCtrl = isMacApp ? 'Cmd' : 'Ctrl'; return ( @@ -61,11 +61,21 @@ export class AboutDialog extends Component {
  • - Focus search field + Toggle focus mode
  • - Search within note + Focus search field +
  • +
  • + + Jump to next match in note + +
  • +
  • + + Jump to previous match in note +
  • {isElectron && (
  • @@ -105,11 +115,13 @@ export class AboutDialog extends Component {
  • - Select previous note + Open note above current one
  • - Select next note + + Open note below current one +
  • @@ -118,9 +130,7 @@ export class AboutDialog extends Component {
  • - Toggle note list -
    - (on narrow screens) + Toggle note list (on narrow screens)
  • @@ -133,7 +143,15 @@ export class AboutDialog extends Component { Create new note
  • - Trash note + + Trash note +
  • {isElectron && (
  • diff --git a/lib/dialogs/keybindings/style.scss b/lib/dialogs/keybindings/style.scss index ab74e1531..90fd6da32 100644 --- a/lib/dialogs/keybindings/style.scss +++ b/lib/dialogs/keybindings/style.scss @@ -1,15 +1,7 @@ .keybindings { .dialog { - max-width: 1120px; + max-width: 500px; margin: auto; - - @media only screen and (max-width: 1150px) { - max-width: 760px; - } - - @media only screen and (max-width: 780px) { - max-width: 480px; - } } .dialog-content { @@ -51,8 +43,9 @@ } .keybindings__key-list { - min-width: 80px; + min-width: 180px; display: inline-block; + text-align: right; } .keybindings__key-description { @@ -65,11 +58,6 @@ max-height: 480px; overflow-y: scroll; - width: 100%; - display: flex; - flex-direction: row; - flex-wrap: wrap; - section { margin-right: 2em; diff --git a/lib/note-detail/index.tsx b/lib/note-detail/index.tsx index 241f15b17..b4cecd103 100644 --- a/lib/note-detail/index.tsx +++ b/lib/note-detail/index.tsx @@ -63,7 +63,7 @@ export class NoteDetail extends Component { // Ensures note gets saved if user abruptly quits the app window.addEventListener('beforeunload', this.queueNoteSync.flush); - window.addEventListener('keydown', this.handlePreviewKeydown, false); + window.addEventListener('keydown', this.handlePreviewKeydown, true); if (previewingMarkdown) { this.updateMarkdown(); @@ -104,7 +104,7 @@ export class NoteDetail extends Component { componentWillUnmount() { window.removeEventListener('beforeunload', this.queueNoteSync.flush); document.removeEventListener('copy', this.copyRenderedNote, false); - window.removeEventListener('keydown', this.handlePreviewKeydown, false); + window.removeEventListener('keydown', this.handlePreviewKeydown, true); } copyRenderedNote = event => { @@ -209,6 +209,9 @@ export class NoteDetail extends Component { cmdOrCtrl && code === 'KeyG' ) { + event.stopPropagation(); + event.preventDefault(); + const matches = this.noteDetail.current.querySelectorAll( 'span.search-match' ); diff --git a/lib/note-editor/index.tsx b/lib/note-editor/index.tsx index 45ba7f395..c891737ad 100644 --- a/lib/note-editor/index.tsx +++ b/lib/note-editor/index.tsx @@ -88,14 +88,6 @@ export class NoteEditor extends Component { return false; } - // open note list - if (this.props.isSmallScreen && cmdOrCtrl && shiftKey && 'KeyL' === code) { - this.props.toggleNoteList(); - event.stopPropagation(); - event.preventDefault(); - return false; - } - // toggle between tag editor and note editor if ( !shiftKey && diff --git a/lib/note-list/index.tsx b/lib/note-list/index.tsx index 34d5739f2..90830af39 100644 --- a/lib/note-list/index.tsx +++ b/lib/note-list/index.tsx @@ -51,6 +51,7 @@ type DispatchProps = { onSelectNote: (note: T.NoteEntity | null) => any; onPinNote: (note: T.NoteEntity, shouldPin: boolean) => any; openNote: (note: T.NoteEntity) => any; + toggleNoteList: () => any; }; type Props = Readonly; @@ -220,6 +221,7 @@ export class NoteList extends Component { openedTag, selectedNote, selectedNoteContent, + showNoteList, showTrash, tagResultsFound, } = nextProps; @@ -229,7 +231,8 @@ export class NoteList extends Component { noteDisplay !== this.props.noteDisplay || notes !== this.props.notes || tagResultsFound !== this.props.tagResultsFound || - selectedNoteContent !== this.props.selectedNoteContent + selectedNoteContent !== this.props.selectedNoteContent || + showNoteList !== this.props.showNoteList ) { heightCache.clearAll(); } @@ -286,7 +289,8 @@ export class NoteList extends Component { prevProps.noteDisplay !== this.props.noteDisplay || prevProps.notes !== this.props.notes || prevProps.tagResultsFound !== this.props.tagResultsFound || - prevProps.selectedNoteContent !== this.props.selectedNoteContent + prevProps.selectedNoteContent !== this.props.selectedNoteContent || + prevProps.showNoteList !== this.props.showNoteList ) { heightCache.clearAll(); } @@ -306,7 +310,7 @@ export class NoteList extends Component { const cmdOrCtrl = ctrlKey || metaKey; if (cmdOrCtrl && shiftKey && code === 'KeyK') { if (-1 === highlightedIndex || index < 0 || !notes[index - 1]?.id) { - return true; + return false; } this.props.onSelectNote(notes[index - 1]); @@ -321,7 +325,7 @@ export class NoteList extends Component { index >= notes.length || !notes[index + 1]?.id ) { - return true; + return false; } this.props.onSelectNote(notes[index + 1]); @@ -330,6 +334,14 @@ export class NoteList extends Component { return false; } + if (isSmallScreen && code === 'KeyL') { + this.props.toggleNoteList(); + + event.stopPropagation(); + event.preventDefault(); + return false; + } + if ( isSmallScreen && showNoteList && @@ -537,6 +549,7 @@ const mapDispatchToProps: S.MapDispatch = ( }, onPinNote: (note, shouldPin) => dispatch(actions.ui.pinNote(note, shouldPin)), openNote: (note: T.NoteEntity) => dispatch(actions.ui.openNote(note)), + toggleNoteList: () => dispatch(actions.ui.toggleNoteList()), }); export default connect(mapStateToProps, mapDispatchToProps)(NoteList); diff --git a/lib/note-toolbar/index.tsx b/lib/note-toolbar/index.tsx index a83365d48..9f392749a 100644 --- a/lib/note-toolbar/index.tsx +++ b/lib/note-toolbar/index.tsx @@ -88,7 +88,7 @@ export class NoteToolbar extends Component { } onClick={this.props.toggleNoteList} - title="Back" + title="Back • Ctrl+Shift+L" /> {markdownEnabled && ( @@ -142,7 +142,7 @@ export class NoteToolbar extends Component { } onClick={this.props.toggleNoteList} - title="Back" + title="Back • Ctrl+Shift+L" />
    From fc4814dfb0aba357a4e628df1519011d63a7d41c Mon Sep 17 00:00:00 2001 From: Jonathan Belcher Date: Wed, 29 Apr 2020 12:14:10 -0400 Subject: [PATCH 6/9] Update version to 1.16.0-beta2 (#2050) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 542da40db..326726e3b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "email": "support@simplenote.com" }, "productName": "Simplenote", - "version": "1.16.0-beta1", + "version": "1.16.0-beta2", "main": "desktop/index.js", "license": "GPL-2.0", "homepage": "https://simplenote.com", From f67151c1677905aeddce8fadcce11598a337c6dd Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Thu, 30 Apr 2020 15:00:46 -0700 Subject: [PATCH 7/9] Fix: Properly filter deleted flag (#2054) After deploying the release candidate to app.simplenote.com we noticed a surge in support requests for missing notes. Upon investigation we discovered that notes with `deleted: 0` were being excluded from the search results; this was due to a strict type comparison of the `deleted` property with the boolean `showTrash` flag. To resolve this issue we have coerced the `deleted` property to a boolean value when inserting a note into the index. --- lib/search/worker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/search/worker.ts b/lib/search/worker.ts index 5f13ad476..015fc09d9 100644 --- a/lib/search/worker.ts +++ b/lib/search/worker.ts @@ -103,6 +103,7 @@ export const updateNote = (noteId: T.EntityId, data) => { { ...data, content: data.content.toLocaleLowerCase(), + deleted: !!data.deleted, tags: noteTags, }, ]); From 75ae94588055c22a1e3149276267fca9f71d0ad3 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Mon, 4 May 2020 17:19:47 +1000 Subject: [PATCH 8/9] Bump version to 1.16.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 641de02c2..41353a00b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "simplenote", - "version": "1.16.0-beta1", + "version": "1.16.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 326726e3b..2e2d77901 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "email": "support@simplenote.com" }, "productName": "Simplenote", - "version": "1.16.0-beta2", + "version": "1.16.0", "main": "desktop/index.js", "license": "GPL-2.0", "homepage": "https://simplenote.com", From b63c980fa277bae2f8067748e91fcf54a1efd168 Mon Sep 17 00:00:00 2001 From: Kat Hagan Date: Mon, 4 May 2020 19:26:58 -0700 Subject: [PATCH 9/9] fix not checking for meta keys on L (#2059) --- lib/note-list/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/note-list/index.tsx b/lib/note-list/index.tsx index 90830af39..110e6f642 100644 --- a/lib/note-list/index.tsx +++ b/lib/note-list/index.tsx @@ -334,7 +334,7 @@ export class NoteList extends Component { return false; } - if (isSmallScreen && code === 'KeyL') { + if (isSmallScreen && cmdOrCtrl && shiftKey && code === 'KeyL') { this.props.toggleNoteList(); event.stopPropagation();