1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 18:26:26 +00:00

Compare commits

..

202 Commits

Author SHA1 Message Date
Kazu Yokomizo
2027f60014 Merge pull request #794 from BoostIO/fix-progress-bar-ui
Fix progress bar ui at Noteitem
2017-08-12 12:17:34 +09:00
Kazu Yokomizo
076edd375f Fix progress bar UI at NoteItem 2017-08-12 12:13:07 +09:00
SuenagaRyota
ab1aa56059 Merge pull request #792 from asmsuechan/add-tests
Add tests
2017-08-12 10:31:42 +09:00
asmsuechan
46f7dfdfeb Change " to ' 2017-08-12 10:17:36 +09:00
asmsuechan
fcaa5e21cf Add tests for RcParser 2017-08-12 09:36:39 +09:00
asmsuechan
1e202db50f Change the directory of RcParser 2017-08-12 09:36:30 +09:00
asmsuechan
9405b95825 Change RcParser testable 2017-08-12 09:11:22 +09:00
asmsuechan
f05e256afc Fix .boostnoterc.sample 2017-08-12 09:08:42 +09:00
asmsuechan
731ffd4a22 Add spec for getTodoStatus 2017-08-12 09:07:58 +09:00
SuenagaRyota
8f4566b7e1 Merge pull request #789 from asmsuechan/try-catch-in-rc-parser
Make RcParser ignore errors at JSON.parse()
2017-08-11 08:38:00 +09:00
asmsuechan
95aec54f60 Make RcParser ignore errors at JSON.parse() 2017-08-11 08:24:08 +09:00
SuenagaRyota
f14ce0d68e Merge pull request #787 from asmsuechan/fix-configmanager
Fix configmanager
2017-08-11 00:41:16 +09:00
asmsuechan
cc1c7f3820 Fix stupid JSON 2017-08-11 00:30:57 +09:00
SuenagaRyota
2df901288a Merge pull request #776 from XGHeaven/master
add todo percentage in item list
2017-08-10 23:39:12 +09:00
asmsuechan
821a7c780e Change variable names 2017-08-10 23:30:42 +09:00
asmsuechan
6e2e48fa64 Fix ConfigManger to load the settings from localStorage properly 2017-08-10 23:19:57 +09:00
Kazu Yokomizo
2864ac88f5 Merge pull request #784 from BoostIO/feature-v0-8-13
v0.8.13
2017-08-10 22:05:33 +09:00
XGHeaven
4a292d6518 add transition for TodoProcess inner bar 2017-08-10 20:00:57 +08:00
XGHeaven
e934182e86 change getTodoState to getTodoStatus 2017-08-10 19:58:58 +08:00
Kazu Yokomizo
d8fa73287b v0.8.13 2017-08-10 19:44:20 +09:00
SuenagaRyota
35938c09e8 Merge pull request #783 from asmsuechan/add-boostnoterc-for-config
Add boostnoterc revival
2017-08-10 16:58:23 +09:00
SuenagaRyota
9eaa90c691 Merge pull request #768 from BoostIO/fix-infoPanel-layout-in-trash
Fixed InfoPanel layout in Trash
2017-08-10 16:52:07 +09:00
Kazu Yokomizo
049835d426 Fix typo “in Trash” to “Trash” 2017-08-10 16:43:25 +09:00
asmsuechan
af91c40406 Remove unused variable 2017-08-10 16:42:14 +09:00
asmsuechan
4940ad6825 Add .boostnoterc.sample 2017-08-10 16:38:20 +09:00
asmsuechan
d02b740300 Fix assignConfigValues because it didn't return proper hash object 2017-08-10 16:37:31 +09:00
asmsuechan
9cb443dc2f Remove unused variable 2017-08-10 15:18:55 +09:00
XGHeaven
1c7cba2951 add todo percentage in item list 2017-08-10 12:31:07 +08:00
asmsuechan
473b80710d Remove RcParser.exec 2017-08-10 11:14:42 +09:00
asmsuechan
2247c0835d Ignore any errors in ~/.boostnoterc 2017-08-10 09:54:56 +09:00
asmsuechan
b7b715ba3d Fix a return value of RcParser.parse 2017-08-10 09:44:00 +09:00
asmsuechan
6c43fb2325 Enable to set configs in ~/.boostnoterc 2017-08-10 09:43:50 +09:00
asmsuechan
a6fe3c27d4 Fix a cyclic object value error 2017-08-10 09:43:19 +09:00
asmsuechan
d47ff96b13 Enable to set configs in ~/.boostnoterc 2017-08-10 09:43:19 +09:00
SuenagaRyota
a0def654bd Merge pull request #782 from MrBMT/update-app-wording
Update application wording
2017-08-10 07:15:18 +09:00
Ben
4873b40e49 Update application text
Updates application text in various places to correct the wording of or better reflect the functionality provided.
2017-08-09 16:48:39 +01:00
SuenagaRyota
0a758f20a7 Merge pull request #780 from asmsuechan/fix-storageKey-undefined
Add storageKey to MarkdownEditor
2017-08-09 23:16:53 +09:00
asmsuechan
5e58d457a3 Add storageKey to MarkdownEditor 2017-08-09 23:12:07 +09:00
SuenagaRyota
0f745361ad Merge pull request #779 from MrBMT/fix-default-fonts
Add Lato font-face definition to main.html
2017-08-09 22:51:43 +09:00
Ben
bf6cae9a0e Add Lato font definition to main.html
Lato is the default "Preview font family" font. However, in the case that Lato is not installed on the user's system, it falls back to using a different font instead of using the font included with the application.
2017-08-09 14:42:07 +01:00
SuenagaRyota
ab640a7676 Merge pull request #777 from MrBMT/finder-fix
Finder UI Fix (My Storage positioning)
2017-08-09 21:04:26 +09:00
Ben
820171e19e Fixes storage positioning
Fixes positioning of the My Storage section on Finder, so that it is not shown over the top of the Trash.
2017-08-09 12:34:14 +01:00
Kazu Yokomizo
f1e9d0ab81 Merge pull request #767 from mrseanbaines/fix-typo
Fixes typo in welcome screen
2017-08-09 11:55:58 +09:00
Sean Baines
0646484c83 Fixes wording on folder delete
"This work will deletes all notes in the folder and can not be undone." to "This will delete all notes in the folder and can not be undone."
2017-08-06 11:34:39 +01:00
Kazu Yokomizo
a27b79c213 Add newline at InfoPanel 2017-08-06 13:59:51 +09:00
Kazu Yokomizo
773a9b4b7f Fixed InfoPanel layout in Trash 2017-08-06 12:56:52 +09:00
Sean Baines
07b838ef7b Fixes typo in welcome screen 2017-08-05 17:17:33 +01:00
SuenagaRyota
85217a7171 Merge pull request #766 from asmsuechan/improve-search
Context search
2017-08-05 22:56:31 +09:00
asmsuechan
886d7b7227 Fix test 2017-08-05 22:48:04 +09:00
asmsuechan
6987b762dd Make context-search work 2017-08-05 22:23:33 +09:00
SuenagaRyota
f32ac81f84 Merge pull request #764 from asmsuechan/fix-noteCount-by-trash
Fix noteCount on a note trased
2017-08-05 22:03:44 +09:00
asmsuechan
87ea66bb92 Change iterate variable 2017-08-05 22:00:12 +09:00
SuenagaRyota
ff6fd62932 Merge pull request #765 from asmsuechan/iss-758
iss #758 Add InfoButton and InfoPanel in Trash
2017-08-05 21:56:22 +09:00
asmsuechan
76728448ff iss #758 Add InfoButton and InfoPanel in SnippetNoteDetail 2017-08-05 17:34:26 +09:00
asmsuechan
3b7225e0fa iss #758 Add InfoButton and InfoPanel in Trash 2017-08-05 17:30:59 +09:00
asmsuechan
d6280f4397 Fix noteCount on a note trased 2017-08-05 17:16:57 +09:00
SuenagaRyota
8df867046f Merge pull request #753 from asmsuechan/work-shortcuts-in-right-click
Change to work ctrl-e and ctrl-w in RIGHTCLICK
2017-08-05 12:05:22 +09:00
SuenagaRyota
331c822816 Merge pull request #754 from asmsuechan/add-print
Add Print
2017-08-05 11:59:16 +09:00
SuenagaRyota
6219173945 Merge pull request #763 from asmsuechan/fix-issue_template
Stress words in ISSUE_TEMPLATE
2017-08-04 08:36:27 +09:00
asmsuechan
6207e02e7f Stress words in ISSUE_TEMPLATE 2017-08-04 08:33:09 +09:00
asmsuechan
537ba537dc Add Print 2017-08-01 19:30:48 +09:00
asmsuechan
3e919241e6 Change to work ctrl-e and ctrl-w in RIGHTCLICK 2017-08-01 09:20:22 +09:00
SuenagaRyota
2324327e7e Merge pull request #749 from asmsuechan/change-order-for-ama-event
Change order for AMA event
2017-07-31 23:08:41 +09:00
asmsuechan
b8374494ea Change order for AMA event 2017-07-31 23:02:49 +09:00
SuenagaRyota
a480ca7b55 Merge pull request #731 from asmsuechan/add-find-storage-path-module
Add find storage path module
2017-07-30 16:15:33 +09:00
Kohei TAKATA
bfd67fb7f1 Merge pull request #735 from BoostIO/feature-v0-8-12
v0.8.12
2017-07-29 15:04:53 +09:00
Kohei TAKATA
e6bd6a5077 v0.8.12 2017-07-29 13:58:11 +09:00
Kohei TAKATA
350af844ca Merge pull request #736 from BoostIO/fix-layout
Fix layout
2017-07-29 13:56:21 +09:00
Kazu Yokomizo
a49d53179a Change “Trashed” to “Trash” 2017-07-29 13:49:45 +09:00
Kazu Yokomizo
e68069fd2f Fix undo button layout at notedetail 2017-07-29 13:40:04 +09:00
SuenagaRyota
a193ba3e6c Merge pull request #732 from asmsuechan/fix-image-path-on-dropped
Make it work on windows
2017-07-26 15:55:30 +09:00
asmsuechan
9034b3ab54 Make it work on windows 2017-07-26 15:47:38 +09:00
asmsuechan
f39b7594ab Add tests for findStorage() 2017-07-26 15:16:21 +09:00
asmsuechan
f79734391e Change to use the module 2017-07-26 15:16:18 +09:00
asmsuechan
e54f516418 Add findStorage() 2017-07-26 14:40:50 +09:00
SuenagaRyota
e86464535d Merge pull request #730 from asmsuechan/make-image-path-relative
Make image path relative
2017-07-26 14:33:41 +09:00
asmsuechan
e8553caa65 Make finder work fine 2017-07-26 14:29:55 +09:00
asmsuechan
044e6b7180 Make image path relative 2017-07-26 13:16:32 +09:00
SuenagaRyota
0266770657 Merge pull request #726 from asmsuechan/fix-default-font-on-windows
iss #155 Change defaut font on windows_
2017-07-25 16:04:12 +09:00
SuenagaRyota
2d6f7c08e8 Merge pull request #728 from asmsuechan/iss-727
iss #727 fix incorrect encoding in link
2017-07-25 15:59:28 +09:00
asmsuechan
0a27819a7f iss #727 fix incorrect encoding in link 2017-07-25 15:35:44 +09:00
SuenagaRyota
3185c25ee1 Merge pull request #724 from BoostIO/fix-button-at-markdown-eidt
Fix hidden button
2017-07-25 14:32:37 +09:00
asmsuechan
820802cdc2 iss #155 Change defaut font on windows_ 2017-07-25 14:04:39 +09:00
Kazu Yokomizo
2c169e6f15 Merge pull request #723 from asmsuechan/fix-typo-for-info-data-collection
Fix typo in InfoTab
2017-07-25 13:45:23 +09:00
Kazu Yokomizo
49be1320f9 Fix hidden button 2017-07-25 13:44:17 +09:00
asmsuechan
6bc4ecce48 Fix typo in InfoTab 2017-07-25 11:57:04 +09:00
SuenagaRyota
0290d23832 Merge pull request #722 from BoostIO/fix-layout
Fix layout
2017-07-25 10:18:12 +09:00
Kazu Yokomizo
e001c97e01 Make padding between Storages at SideNav. 2017-07-24 19:18:48 +09:00
Kazu Yokomizo
976d1bb4f3 Delete unnecessary comma. 2017-07-24 19:09:13 +09:00
Kazu Yokomizo
dee6495b08 Fix typo 2017-07-24 18:12:33 +09:00
Kazu Yokomizo
4a77f250f1 Fix button layout 2017-07-24 17:55:47 +09:00
Kazu Yokomizo
c697f19642 Fix layout at export note in InfoPanel 2017-07-24 17:00:08 +09:00
Kazu Yokomizo
f7d1f9e949 Fix InfoTab layout 2017-07-24 14:47:10 +09:00
Kazu Yokomizo
27b9952f8e Change policy content 2017-07-24 14:39:43 +09:00
Kazu Yokomizo
961dab4a97 Merge pull request #721 from BoostIO/udpate-slack-link
Update readme
2017-07-24 12:11:56 +09:00
Kazu Yokomizo
930b6bc927 Update readme
Update the slack link.
2017-07-24 11:53:39 +09:00
SuenagaRyota
ed7d8258cf Merge pull request #720 from asmsuechan/goodby-ctrl-g
Goodbye Ctrl-G
2017-07-22 16:44:48 +09:00
asmsuechan
762425125f Remove Ctrl-G because it's unneccessary and conflicts with CodeMirror 2017-07-22 16:41:08 +09:00
SuenagaRyota
03bdf0c653 Merge pull request #719 from asmsuechan/fix-inseration-image
Fix inseration position
2017-07-22 16:13:25 +09:00
asmsuechan
7002026190 Fix inseration position 2017-07-22 16:05:14 +09:00
SuenagaRyota
b35395e6bd Merge pull request #709 from asmsuechan/add-exports-to-infoPanel
Add exports to infoPanel
2017-07-22 15:47:01 +09:00
SuenagaRyota
b74fb76d03 Merge pull request #718 from asmsuechan/fix-typos
Fix typos Dynamit to Dynamic
2017-07-22 15:42:49 +09:00
asmsuechan
72d2df465b Fix typos Dynamit to Dynamic 2017-07-22 15:33:56 +09:00
SuenagaRyota
2592c943f7 Merge pull request #717 from asmsuechan/fix-a-bug-on-click
Fix a bug on click
2017-07-22 15:28:38 +09:00
asmsuechan
7b3a3ba200 Fix by eslint 2017-07-22 15:24:51 +09:00
asmsuechan
8369832585 Fix a bug on click 2017-07-22 15:11:59 +09:00
SuenagaRyota
d94a674343 Merge pull request #716 from asmsuechan/change-note-link-content
Change ["title"](note-hash) to [the exact title](note-hash)
2017-07-22 15:01:04 +09:00
SuenagaRyota
260611ffd6 Merge pull request #715 from asmsuechan/add-checkbox-for-ama
Add checkbox for ama
2017-07-22 14:57:31 +09:00
asmsuechan
690549b57f Change a word 2017-07-22 14:34:28 +09:00
asmsuechan
5d9aeb4c04 Fix typo 2017-07-22 14:32:18 +09:00
asmsuechan
eddfdea2ca Fix a closing tag and a condition 2017-07-22 14:20:42 +09:00
asmsuechan
a40385f87f Add policy 2017-07-22 13:58:02 +09:00
asmsuechan
0123526c98 Change ["title"](note-hash) to [the exact title](note-hash) 2017-07-22 11:29:39 +09:00
asmsuechan
275e3317a3 Add checkbox for ama 2017-07-22 08:59:27 +09:00
SuenagaRyota
d0b835a825 Merge pull request #710 from asmsuechan/fix-image-dropped
Change to create a new directory when storage/images does not exist
2017-07-16 15:52:03 +09:00
asmsuechan
f450260ff8 Fix a prop name noteKey to noteLink 2017-07-16 15:16:59 +09:00
asmsuechan
5f7b119e5c Remove an useless 'cancel' button 2017-07-16 15:06:22 +09:00
asmsuechan
bb9eb494e9 Change to create a new directory when storage/images does not exist 2017-07-16 15:02:18 +09:00
asmsuechan
6ea2b5e1d9 Add exports to infoPanel 2017-07-15 19:33:58 +09:00
SuenagaRyota
b21baf1ce5 Merge pull request #708 from asmsuechan/change-note-hash
Change noteHash to noteLink in the input in InfoPanel
2017-07-15 16:57:55 +09:00
SuenagaRyota
4c3fd461e4 Merge pull request #707 from asmsuechan/remove-dialogbox-from-trash
Remove a dialogbox from onTrashButtonClick
2017-07-15 14:47:38 +09:00
asmsuechan
8365a60d5d Change noteHash to noteLink in the input in InfoPanel 2017-07-15 13:41:22 +09:00
asmsuechan
804ac1aa96 Remove a dialogbox from onTrashButtonClick 2017-07-15 12:52:55 +09:00
SuenagaRyota
49fd2cfc4d Merge pull request #706 from asmsuechan/change-shotrcut-ctrl-u-to-ctrl-k
Change the keymap of Ctrl-U to Ctrl-K
2017-07-15 12:51:40 +09:00
asmsuechan
2bb2a52f27 Change the keymap of Ctrl-U to Ctrl-K 2017-07-14 18:18:38 +09:00
Kazu Yokomizo
8d71b28afa Merge pull request #705 from BoostIO/udpate-readme
Fix slack link
2017-07-13 16:23:34 +09:00
Kazu Yokomizo
86eac7054d Update Readmd 2017-07-13 15:41:56 +09:00
SuenagaRyota
dccb92d72b Merge pull request #297 from asmsuechan/add-trash-can
Add trash can
2017-07-12 15:53:49 +09:00
asmsuechan
2e628de9c6 Restore missing components 2017-07-12 15:48:11 +09:00
asmsuechan
2d243abc12 Add condition 2017-07-12 15:48:11 +09:00
asmsuechan
ae08bf4d7a Escape from addition a note when the note is in the trashbox 2017-07-12 15:48:11 +09:00
asmsuechan
cbff5fb585 Fix indents pointed by lint 2017-07-12 15:48:11 +09:00
asmsuechan
2650cc2f1c Add trash can 2017-07-12 15:48:08 +09:00
Kazu Yokomizo
ec560ceab1 Merge pull request #702 from BoostIO/update-readme
Update Readme
2017-07-11 01:01:19 +09:00
Kazu Yokomizo
ad17cb8837 Update Readme 2017-07-11 00:55:21 +09:00
Kazu Yokomizo
4f98d9641a Merge pull request #698 from BoostIO/update-layout
Update layout
2017-07-11 00:20:59 +09:00
Kazu Yokomizo
17535ccd4c Add Info Panel at SnippetDetail 2017-07-10 17:43:20 +09:00
Kazu Yokomizo
110c1ea337 Delete update date at under of NoteDetail 2017-07-10 17:13:18 +09:00
Kazu Yokomizo
7e087bfbab Fix info panel layout 2017-07-10 17:07:44 +09:00
SuenagaRyota
85e0d4b922 Merge pull request #697 from asmsuechan/remove-sharp-from-hash
Remove sharp from note hash on list:jump
2017-07-10 16:43:02 +09:00
asmsuechan
265262ccbf Remove sharp from note hash on list:jump 2017-07-10 16:37:07 +09:00
Kazu Yokomizo
345008e9b6 Fix info area layout at NoteDetail 2017-07-10 16:28:50 +09:00
SuenagaRyota
849aa05d76 Merge pull request #696 from asmsuechan/replace-cm-searchbox-to-official-search-addon
Replace cm searchbox to official search addon
2017-07-10 14:21:47 +09:00
asmsuechan
5ff5ec6a71 Remove cm-searchbox 2017-07-09 22:47:15 +09:00
asmsuechan
684c3f64aa Add search addon 2017-07-09 22:46:23 +09:00
SuenagaRyota
4ff73ede59 Merge pull request #695 from asmsuechan/bugfix-on-click-event
Fix an error on click event
2017-07-09 18:20:51 +09:00
asmsuechan
7302d83f60 Fix a bug on click event 2017-07-09 18:08:33 +09:00
SuenagaRyota
f9836fd66e Merge pull request #692 from asmsuechan/add-info-button
Add info button
2017-07-09 17:16:06 +09:00
SuenagaRyota
c0f05695fe Merge pull request #686 from asmsuechan/add-search-box
Add search-box
2017-07-09 17:15:57 +09:00
SuenagaRyota
e50a1172d6 Merge pull request #693 from asmsuechan/feature-links-among-notes
Feature links among notes
2017-07-09 17:15:50 +09:00
Kazu Yokomizo
7a4234e73c Merge pull request #690 from BoostIO/update-layout
Fix layout
2017-07-09 13:29:00 +09:00
Kazu Yokomizo
4b9640e5a3 Fix star position at NoteList 2017-07-09 12:56:02 +09:00
Kazu Yokomizo
4b58054100 Fix tag area layout at NoteItem 2017-07-09 12:46:46 +09:00
Kazu Yokomizo
8951dbf4ed Fix star position at NoteList 2017-07-08 16:05:45 +09:00
Kazu Yokomizo
5047bc94eb Fix search area layout 2017-07-08 15:58:40 +09:00
asmsuechan
75fb29c594 Change == to === 2017-07-08 15:44:20 +09:00
asmsuechan
bd75f7fd2c Remove a display of a note hash 2017-07-08 14:08:28 +09:00
asmsuechan
8b8cb3c9b4 Change styleName in each styles 2017-07-08 14:08:28 +09:00
asmsuechan
b479b21c37 Remove a blank line 2017-07-08 14:08:28 +09:00
asmsuechan
525c490704 Remove console.log 2017-07-08 14:08:28 +09:00
asmsuechan
2e3599d005 Add a feature which enables to link between notes 2017-07-08 14:08:28 +09:00
asmsuechan
f005bb1e46 hoge 2017-07-08 14:02:03 +09:00
asmsuechan
21f96febdb Fix some pointed by lint 2017-07-08 13:37:24 +09:00
asmsuechan
805829be78 Make InfoButton component stateless 2017-07-08 13:32:37 +09:00
asmsuechan
a7bd3f253f Rename getLastUpdated() to formatDate() 2017-07-08 13:16:19 +09:00
asmsuechan
81e8a290f0 Add infomation panel 2017-07-08 13:16:02 +09:00
Kazu Yokomizo
f46a967b6e Fix an error 2017-07-08 12:31:21 +09:00
Kazu Yokomizo
b78d9534aa Fix layout 2017-07-08 02:18:33 +09:00
SuenagaRyota
bdefaf7427 Merge pull request #681 from BoostIO/edit-initial-files
Edit initial files
2017-07-07 20:59:50 +09:00
SuenagaRyota
43550c7dec Merge pull request #688 from asmsuechan/remove-handle-note-context-menu
Remove the context menu for deletion
2017-07-07 20:12:11 +09:00
asmsuechan
1b07d393f2 Rename handleDeleteButtonClick to handleTrashButtonClick 2017-07-07 20:04:47 +09:00
asmsuechan
44fc356775 Remove the context menu for deletion 2017-07-07 19:45:02 +09:00
SuenagaRyota
5623c68170 Merge pull request #684 from BoostIO/change-menu-to-preferences
Change “Menu” to “Preferences”, and icon.
2017-07-07 18:11:01 +09:00
asmsuechan
d5f82943cf Edit style 2017-07-07 18:06:08 +09:00
asmsuechan
96a020341d Add search-box 2017-07-07 17:59:01 +09:00
Kazu Yokomizo
99b5f75763 Change “Menu” to “Preferences”, and icon. 2017-07-06 14:27:18 +09:00
SuenagaRyota
a128ff7cd8 Merge pull request #683 from asmsuechan/add-iss_template.md
Add issue template
2017-07-06 13:53:26 +09:00
Kazu Yokomizo
59329cc5da Fix typo 2017-07-06 13:50:39 +09:00
asmsuechan
ecd5daaf55 Add issue template 2017-07-06 13:44:19 +09:00
Kazu Yokomizo
514232d720 Merge pull request #682 from BoostIO/update-slack-link
Update slack link
2017-07-06 13:29:39 +09:00
Kazu Yokomizo
93abfe3202 Update slack link 2017-07-06 13:23:22 +09:00
Kazu Yokomizo
4d9e0e3bd7 Change default theme at editor and code-block 2017-07-06 02:32:14 +09:00
Kazu Yokomizo
75d9bf8e38 Edit initial files 2017-07-06 02:31:41 +09:00
SuenagaRyota
ccb9752254 Merge pull request #678 from asmsuechan/remove-e2e-document
Remove e2e documents
2017-07-05 13:38:42 +09:00
asmsuechan
0f2ca19c6c Remove the script of e2e test 2017-07-05 13:33:07 +09:00
asmsuechan
d5a77aade4 Remove testing.md 2017-07-05 13:32:06 +09:00
SuenagaRyota
3c89e6a128 Merge pull request #672 from asmsuechan/componentnize-top-bar-of-note-detail
Componentnize TrashButton
2017-07-02 22:29:14 +09:00
SuenagaRyota
a36be79977 Merge pull request #667 from asmsuechan/randomize-image-name
Randomize the image name when it's dropped
2017-07-02 22:22:23 +09:00
asmsuechan
617f0e0f9c Remove duplicated styles 2017-07-02 22:13:35 +09:00
asmsuechan
0db1a94105 Replace a button to TrashButton component 2017-07-02 22:13:35 +09:00
asmsuechan
f29f97a00f Add TrashButton component 2017-07-02 22:13:32 +09:00
asmsuechan
032b5a59f2 Remove encodeURI 2017-07-01 18:07:16 +09:00
SuenagaRyota
1e5bc395ac Merge pull request #671 from asmsuechan/goodbye-spectron
Goodbye spectron
2017-07-01 12:43:06 +09:00
asmsuechan
fef4afe660 Change .travis.yml 2017-07-01 12:02:52 +09:00
asmsuechan
679ed1eacf Remove e2e tests 2017-07-01 12:02:52 +09:00
asmsuechan
78a9320017 Remove spectron 2017-07-01 12:01:16 +09:00
asmsuechan
927981bf30 Randomize the image name when it's dropped 2017-06-28 13:05:40 +09:00
Kazu Yokomizo
70ea2f6c14 Merge pull request #665 from BoostIO/update-slack-link
Update slack link
2017-06-27 13:46:57 +09:00
Kazu Yokomizo
a6779414ff Delete readme.ja 2017-06-27 13:34:25 +09:00
Kazu Yokomizo
b62fcf523a Update slack link 2017-06-27 13:33:48 +09:00
Kazu Yokomizo
d0bbea5a97 Merge pull request #664 from asmsuechan/auth-aws-only-production
Exclude auth of aws only production
2017-06-26 15:38:33 +09:00
asmsuechan
212d7027fc Exclude auth of aws only production 2017-06-26 15:33:58 +09:00
89 changed files with 1483 additions and 1024 deletions

33
.boostnoterc.sample Normal file
View File

@@ -0,0 +1,33 @@
{
"amaEnabled": true,
"editor": {
"fontFamily": "Monaco, Consolas",
"fontSize": "14",
"indentSize": "2",
"indentType": "space",
"keyMap": "vim",
"switchPreview": "BLUR",
"theme": "monokai"
},
"hotkey": {
"toggleFinder": "Cmd + Alt + S",
"toggleMain": "Cmd + Alt + L"
},
"isSideNavFolded": false,
"listStyle": "DEFAULT",
"listWidth": 174,
"navWidth": 200,
"preview": {
"codeBlockTheme": "dracula",
"fontFamily": "Lato",
"fontSize": "14",
"lineNumber": true
},
"sortBy": "UPDATED_AT",
"ui": {
"defaultNote": "ALWAYS_ASK",
"disableDirectWrite": false,
"theme": "default"
},
"zoom": 1
}

View File

@@ -1,26 +1,6 @@
language: node_js
# To fix the npm version in 4.x
# refs: https://github.com/travis-ci/travis-ci/issues/4653#issuecomment-194051953
before_install: 'if [[ `npm -v` != 4* ]]; then npm i -g npm@4; fi'
matrix:
include:
- os: osx
install:
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then yarn; fi'
node_js:
- 'stable'
- 'lts/*'
script:
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" && ${TRAVIS_NODE_VERSION} = "stable" ]]; then
npm run lint;
npm run test;
./script/e2e-runner.sh;
fi'
- os: linux
node_js:
- 'stable'
- 'lts/*'
script:
- 'npm run lint'
- 'npm run test'
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" && ${TRAVIS_NODE_VERSION} = "stable" ]]; then ./script/e2e-runner.sh; fi'
node_js:
- 'stable'
- 'lts/*'
script: npm run lint && npm run test

1
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1 @@
Please paste some **screenshots** with the **developer tool** open if you report a bug.

View File

@@ -192,15 +192,16 @@ export default class CodeEditor extends React.Component {
const imagePath = e.dataTransfer.files[0].path
const filename = path.basename(imagePath)
copyImage(imagePath, this.props.storageKey).then((imagePathInTheStorage) => {
const imageMd = `![${encodeURI(filename)}](${imagePathInTheStorage})`
copyImage(imagePath, this.props.storageKey).then((imagePath) => {
const imageMd = `![${filename}](${path.join('/:storage', imagePath)})`
this.insertImageMd(imageMd)
})
}
insertImageMd (imageMd) {
const textarea = this.editor.getInputField()
const cm = this.editor
cm.setValue(cm.getValue() + imageMd)
textarea.value = `${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`
}
render () {

View File

@@ -4,6 +4,8 @@ import styles from './MarkdownEditor.styl'
import CodeEditor from 'browser/components/CodeEditor'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import eventEmitter from 'browser/main/lib/eventEmitter'
import { findStorage } from 'browser/lib/findStorage'
const _ = require('lodash')
class MarkdownEditor extends React.Component {
constructor (props) {
@@ -79,7 +81,6 @@ class MarkdownEditor extends React.Component {
if (newStatus === 'CODE') {
this.refs.code.focus()
} else {
this.refs.code.blur()
this.refs.preview.focus()
}
eventEmitter.emit('topbar:togglelockbutton', this.state.status)
@@ -162,15 +163,18 @@ class MarkdownEditor extends React.Component {
}
handleKeyDown (e) {
let { config } = this.props
if (this.state.status !== 'CODE') return false
const keyPressed = this.state.keyPressed
keyPressed.add(e.keyCode)
this.setState({ keyPressed })
let isNoteHandlerKey = (el) => { return keyPressed.has(el) }
// These conditions are for ctrl-e and ctrl-w
if (keyPressed.size === this.escapeFromEditor.length &&
!this.state.isLocked && this.state.status === 'CODE' &&
this.escapeFromEditor.every(isNoteHandlerKey)) {
document.activeElement.blur()
this.handleContextMenu()
if (config.editor.switchPreview === 'BLUR') document.activeElement.blur()
}
if (keyPressed.size === this.supportMdSelectionBold.length && this.supportMdSelectionBold.every(isNoteHandlerKey)) {
this.addMdAroundWord('**')
@@ -213,6 +217,8 @@ class MarkdownEditor extends React.Component {
let previewStyle = {}
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
const storage = findStorage(storageKey)
return (
<div className={className == null
? 'MarkdownEditor'
@@ -260,6 +266,7 @@ class MarkdownEditor extends React.Component {
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
storagePath={storage.path}
/>
</div>
)

View File

@@ -108,6 +108,9 @@ export default class MarkdownPreview extends React.Component {
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
this.saveAsTextHandler = () => this.handleSaveAsText()
this.saveAsMdHandler = () => this.handleSaveAsMd()
this.printHandler = () => this.handlePrint()
this.linkClickHandler = this.handlelinkClick.bind(this)
}
handlePreviewAnchorClick (e) {
@@ -160,6 +163,10 @@ export default class MarkdownPreview extends React.Component {
this.exportAsDocument('md')
}
handlePrint () {
this.refs.root.contentWindow.print()
}
exportAsDocument (fileType) {
const options = {
filters: [
@@ -196,6 +203,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler)
eventEmitter.on('export:save-text', this.saveAsTextHandler)
eventEmitter.on('export:save-md', this.saveAsMdHandler)
eventEmitter.on('print', this.printHandler)
}
componentWillUnmount () {
@@ -206,6 +214,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler)
eventEmitter.off('export:save-text', this.saveAsTextHandler)
eventEmitter.off('export:save-md', this.saveAsMdHandler)
eventEmitter.off('print', this.printHandler)
}
componentDidUpdate (prevProps) {
@@ -249,7 +258,11 @@ export default class MarkdownPreview extends React.Component {
el.removeEventListener('click', this.checkboxClickHandler)
})
let { value, theme, indentSize, codeBlockTheme } = this.props
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
el.removeEventListener('click', this.linkClickHandler)
})
let { value, theme, indentSize, codeBlockTheme, storagePath } = this.props
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
@@ -273,6 +286,15 @@ export default class MarkdownPreview extends React.Component {
el.addEventListener('click', this.checkboxClickHandler)
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
el.addEventListener('click', this.linkClickHandler)
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => {
if (!/\/:storage/.test(el.src)) return
el.src = `file:///${path.join(storagePath, 'images', path.basename(el.src))}`
})
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)
? codeBlockTheme
: 'default'
@@ -373,6 +395,14 @@ export default class MarkdownPreview extends React.Component {
return new window.Notification(title, options)
}
handlelinkClick (e) {
const noteHash = e.target.href.split('/').pop()
const regexIsNoteLink = /^(.{20})-(.{20})$/
if (regexIsNoteLink.test(noteHash)) {
eventEmitter.emit('list:jump', noteHash)
}
}
render () {
let { className, style, tabIndex } = this.props
return (
@@ -394,5 +424,6 @@ MarkdownPreview.propTypes = {
onMouseUp: PropTypes.func,
onMouseDown: PropTypes.func,
className: PropTypes.string,
value: PropTypes.string
value: PropTypes.string,
storagePath: PropTypes.string
}

View File

@@ -4,7 +4,9 @@
import React, { PropTypes } from 'react'
import { isArray } from 'lodash'
import CSSModules from 'browser/lib/CSSModules'
import { getTodoStatus } from 'browser/lib/getTodoStatus'
import styles from './NoteItem.styl'
import TodoProcess from './TodoProcess'
/**
* @description Tag element component.
@@ -39,18 +41,16 @@ const TagElementList = (tags) => {
* @param {boolean} isActive
* @param {Object} note
* @param {Function} handleNoteClick
* @param {Function} handleNoteContextMenu
* @param {Function} handleDragStart
* @param {string} dateDisplay
*/
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteContextMenu, handleDragStart }) => (
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleDragStart }) => (
<div styleName={isActive
? 'item--active'
: 'item'
}
key={`${note.storage}-${note.key}`}
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
onDragStart={e => handleDragStart(e, note)}
draggable='true'
>
@@ -70,6 +70,10 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont
{note.isStarred
? <i styleName='item-star' className='fa fa-star' /> : ''
}
{note.type === 'MARKDOWN_NOTE'
? <TodoProcess todoStatus={getTodoStatus(note.content)} />
: ''
}
<div styleName='item-bottom'>
<div styleName='item-bottom-tagList'>
{note.tags.length > 0
@@ -91,10 +95,10 @@ NoteItem.propTypes = {
type: PropTypes.string.isRequired,
title: PropTypes.string.isrequired,
tags: PropTypes.array,
isStarred: PropTypes.bool.isRequired
isStarred: PropTypes.bool.isRequired,
isTrashed: PropTypes.bool.isRequired
}),
handleNoteClick: PropTypes.func.isRequired,
handleNoteContextMenu: PropTypes.func.isRequired,
handleDragStart: PropTypes.func.isRequired,
handleDragEnd: PropTypes.func.isRequired
}

View File

@@ -39,6 +39,7 @@ $control-height = 30px
.item-wrapper
padding 15px 0
border-bottom $ui-border
position relative
.item--active
@extend .item
@@ -66,7 +67,7 @@ $control-height = 30px
color $ui-inactive-text-color
.item-title
font-size 13px
font-size 14px
position relative
top -12px
left 20px
@@ -92,11 +93,12 @@ $control-height = 30px
flex 1
overflow ellipsis
line-height 20px
padding-top 2px
padding-top 7px
padding-left 2px
margin-right 27px
.item-bottom-tagList-item
font-size 10px
font-size 11px
margin-right 8px
padding 0
height 20px
@@ -109,14 +111,14 @@ $control-height = 30px
.item-bottom-time
color $ui-inactive-text-color
font-size 10px
font-size 11px
padding-left 2px
padding-bottom 2px
.item-star
position absolute
top 34px
left 5px
right -20px
bottom 2px
width 34px
height 34px
color alpha($ui-favorite-star-button-color, 60%)

View File

@@ -10,17 +10,15 @@ import styles from './NoteItemSimple.styl'
* @param {boolean} isActive
* @param {Object} note
* @param {Function} handleNoteClick
* @param {Function} handleNoteContextMenu
* @param {Function} handleDragStart
*/
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenum, handleDragStart }) => (
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleDragStart }) => (
<div styleName={isActive
? 'item-simple--active'
: 'item-simple'
}
key={`${note.storage}-${note.key}`}
onClick={e => handleNoteClick(e, `${note.storage}-${note.key}`)}
onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)}
onDragStart={e => handleDragStart(e, note)}
draggable='true'
>
@@ -46,7 +44,6 @@ NoteItemSimple.propTypes = {
title: PropTypes.string.isrequired
}),
handleNoteClick: PropTypes.func.isRequired,
handleNoteContextMenu: PropTypes.func.isRequired,
handleDragStart: PropTypes.func.isRequired
}

View File

@@ -7,7 +7,7 @@ $control-height = 30px
.item-simple
position relative
padding 0 25px
padding 0 20px
user-select none
cursor pointer
background-color $ui-noteList-backgroundColor
@@ -40,7 +40,7 @@ $control-height = 30px
background-color $ui-button--active-backgroundColor
.item-simple-title
font-size 12px
font-size 13px
height 40px
box-sizing border-box
line-height 24px
@@ -48,6 +48,7 @@ $control-height = 30px
overflow ellipsis
color $ui-inactive-text-color
border-bottom $ui-border
position relative
.item-simple-title-icon
font-size 12px

View File

@@ -15,7 +15,7 @@ import styles from './SideNavFilter.styl'
*/
const SideNavFilter = ({
isFolded, isHomeActive, handleAllNotesButtonClick,
isStarredActive, handleStarredButtonClick
isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick
}) => (
<div styleName={isFolded ? 'menu--folded' : 'menu'}>
<button styleName={isHomeActive ? 'menu-button--active' : 'menu-button'}
@@ -30,6 +30,12 @@ const SideNavFilter = ({
<i className='fa fa-star fa-fw' />
<span styleName='menu-button-label'>Starred</span>
</button>
<button styleName={isTrashedActive ? 'menu-button--active' : 'menu-button'}
onClick={handleTrashedButtonClick}
>
<i className='fa fa-trash fa-fw' />
<span styleName='menu-button-label'>Trash</span>
</button>
</div>
)
@@ -38,7 +44,9 @@ SideNavFilter.propTypes = {
isHomeActive: PropTypes.bool.isRequired,
handleAllNotesButtonClick: PropTypes.func.isRequired,
isStarredActive: PropTypes.bool.isRequired,
handleStarredButtonClick: PropTypes.func.isRequired
isTrashedActive: PropTypes.bool.isRequired,
handleStarredButtonClick: PropTypes.func.isRequired,
handleTrashdButtonClick: PropTypes.func.isRequired
}
export default CSSModules(SideNavFilter, styles)

View File

@@ -0,0 +1,33 @@
/**
* @fileoverview Percentage of todo achievement.
*/
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './TodoProcess.styl'
const TodoProcess = ({
todoStatus: {
total: totalTodo,
completed: completedTodo
}
}) => (
<div styleName='todo-process' style={{display: totalTodo > 0 ? '' : 'none'}}>
<div styleName='todo-process-text'>
<i className='fa fa-fw fa-check-square-o' />
{completedTodo} of {totalTodo}
</div>
<div styleName='todo-process-bar'>
<div styleName='todo-process-bar--inner' style={{width: parseInt(completedTodo / totalTodo * 100) + '%'}} />
</div>
</div>
)
TodoProcess.propTypes = {
todoStatus: {
total: PropTypes.number.isRequired,
completed: PropTypes.number.isRequired
}
}
export default CSSModules(TodoProcess, styles)

View File

@@ -0,0 +1,45 @@
.todo-process
font-size 12px
display flex
padding-top 15px
width 85%
.todo-process-text
display inline-block
padding-right 10px
white-space nowrap
text-overflow ellipsis
color $ui-inactive-text-color
i
color $ui-inactive-text-color
padding-right 5px
.todo-process-bar
display inline-block
margin auto
height 4px
border-radius 10px
background-color #DADFE1
border-radius 2px
flex-grow 1
border 1px solid alpha(#6C7A89, 10%)
.todo-process-bar--inner
height 100%
border-radius 5px
background-color #6C7A89
transition 0.3s
body[data-theme="dark"]
.todo-process
color $ui-dark-text-color
.todo-process-bar
background-color #363A3D
.todo-process-text
color $ui-inactive-text-color
.todo-process-bar--inner
background-color: alpha(#939395, 50%)

View File

@@ -64,7 +64,7 @@ $list-width = 250px
.result-nav-storageList
absolute bottom left right
top 80px + 32px + 10px + 10px
top 110px + 32px + 10px + 10px
overflow-y auto
.result-list

View File

@@ -5,6 +5,7 @@ import MarkdownPreview from 'browser/components/MarkdownPreview'
import MarkdownEditor from 'browser/components/MarkdownEditor'
import CodeEditor from 'browser/components/CodeEditor'
import CodeMirror from 'codemirror'
import { findStorage } from 'browser/lib/findStorage'
const electron = require('electron')
const { clipboard } = electron
@@ -106,6 +107,8 @@ class NoteDetail extends React.Component {
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
const storage = findStorage(note.storage)
if (note.type === 'SNIPPET_NOTE') {
let tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
@@ -143,6 +146,7 @@ class NoteDetail extends React.Component {
config={config}
value={snippet.content}
ref={'code-' + index}
storageKey={note.storage}
/>
: <CodeEditor styleName='tabView-content'
mode={snippet.mode}
@@ -192,6 +196,7 @@ class NoteDetail extends React.Component {
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
value={note.content}
storagePath={storage.path}
/>
)
}

View File

@@ -70,7 +70,6 @@ class NoteList extends React.Component {
dateDisplay={dateDisplay}
key={key}
handleNoteClick={(e) => this.props.handleNoteClick(e, _index)}
handleNoteContextMenu={() => ''}
/>
)
})

View File

@@ -95,7 +95,7 @@ class FinderMain extends React.Component {
if (e.keyCode === 13) {
this.refs.detail.saveToClipboard()
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('COPY_FINDER')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('COPY_FINDER')
hideFinder()
e.preventDefault()
}

21
browser/lib/RcParser.js Normal file
View File

@@ -0,0 +1,21 @@
import path from 'path'
import sander from 'sander'
const BOOSTNOTERC = '.boostnoterc'
const homePath = global.process.env.HOME || global.process.env.USERPROFILE
const _boostnotercPath = path.join(homePath, BOOSTNOTERC)
export function parse (boostnotercPath = _boostnotercPath) {
if (!sander.existsSync(boostnotercPath)) return {}
try {
return JSON.parse(sander.readFileSync(boostnotercPath).toString())
} catch (e) {
console.warn(e)
console.warn('Your .boostnoterc is broken so it\'s not used.')
return {}
}
}
export default {
parse
}

View File

@@ -8,7 +8,7 @@ import moment from 'moment'
* @param {mixed}
* @return {string}
*/
export function getLastUpdated (date) {
export function formatDate (date) {
const m = moment(date)
if (!m.isValid()) {
throw Error('Invalid argument.')

View File

@@ -0,0 +1,14 @@
const _ = require('lodash')
export function findStorage (storageKey) {
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
const storage = _.find(cachedStorageList, {key: storageKey})
if (storage === undefined) throw new Error('Target storage doesn\'t exist.')
return storage
}
export default {
findStorage
}

View File

@@ -0,0 +1,25 @@
export function getTodoStatus (content) {
let splitted = content.split('\n')
let numberOfTodo = 0
let numberOfCompletedTodo = 0
splitted.forEach((line) => {
let trimmedLine = line.trim()
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
numberOfTodo++
}
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) {
numberOfCompletedTodo++
}
})
return {
total: numberOfTodo,
completed: numberOfCompletedTodo
}
}
export function getTodoPercentageOfCompleted (content) {
const state = getTodoStatus(content)
return Math.floor(state.completed / state.total * 100)
}

View File

@@ -159,7 +159,8 @@ function strip (input) {
const markdown = {
render: function markdown (content) {
if (!_.isString(content)) content = ''
return md.render(content)
const renderedContent = md.render(content)
return md.normalizeLinkText(renderedContent)
},
strip
}

View File

@@ -1,7 +1,6 @@
import _ from 'lodash'
export default function searchFromNotes (data, search) {
let notes = data.noteMap.map((note) => note)
export default function searchFromNotes (notes, search) {
if (search.trim().length === 0) return []
let searchBlocks = search.split(' ')
searchBlocks.forEach((block) => {

View File

@@ -1,7 +1,7 @@
.root
position relative
border solid 1px transparent
line-height 34px
line-height 26px
vertical-align middle
border-radius 2px
transition 0.15s

View File

@@ -0,0 +1,19 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoButton.styl'
const InfoButton = ({
onClick
}) => (
<button styleName='control-infoButton'
onClick={onClick}
>
<i className='fa fa-info infoButton' styleName='info-button' />
</button>
)
InfoButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(InfoButton, styles)

View File

@@ -0,0 +1,21 @@
.control-infoButton
float right
topBarButtonLight()
.control-infoPanel
position fixed
pointer-events none
top 50px
z-index 200
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.infoButton
padding 0px
margin 15px 0
body[data-theme="dark"]
.control-infoButton
topBarButtonDark()

View File

@@ -0,0 +1,79 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl'
const InfoPanel = ({
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt
}) => (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div styleName='group-section'>
<div styleName='group-section-label'>
Storage
</div>
<div styleName='group-section-control'>
{storageName}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Folder
</div>
<div styleName='group-section-control'>
{folderName}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Created
</div>
<div styleName='group-section-control'>
{createdAt}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Updated
</div>
<div styleName='group-section-control'>
{updatedAt}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Note Link
</div>
<div styleName='group-section-control'>
<input value={noteLink} onClick={(e) => { e.target.select() }} />
</div>
</div>
<div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o fa-fw' />
<p>.md</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o fa-fw' />
<p>.txt</p>
</button>
<button styleName='export--unable'>
<i className='fa fa-file-pdf-o fa-fw' />
<p>.pdf</p>
</button>
</div>
</div>
)
InfoPanel.propTypes = {
storageName: PropTypes.string.isRequired,
folderName: PropTypes.string.isRequired,
noteLink: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
exportAsMd: PropTypes.func.isRequired,
exportAsTxt: PropTypes.func.isRequired
}
export default CSSModules(InfoPanel, styles)

View File

@@ -0,0 +1,124 @@
.control-infoPanel
position fixed
pointer-events none
top 50px
z-index 200
line-height normal
border-radius 4px
opacity 0
transition 0.2s
.control-infoButton-panel
z-index 200
margin-top 45px
margin-left -210px
position absolute
padding 20px 20px 0 20px
width 340px
background-color $ui-noteList-backgroundColor
border 1px solid $border-color
.control-infoButton-panel-trash
z-index 200
margin-top 45px
margin-left -230px
position absolute
padding 20px 20px 0 20px
width 320px
background-color $ui-noteList-backgroundColor
border 1px solid $border-color
.group-section
display flex
line-height 30px
font-size 13px
.group-section-label
width 70px
height 20px
text-align left
margin-right 50px
font-size 13px
color $ui-inactive-text-color
.group-section-control
flex 1
font-size 13px
color $ui-text-color
.group-section-control input
width 160px
height 25px
.group-section-control text
color #EA4447
font-weight 600
font-size 14px
width 70px
height 25px
background-color rgba(226,33,113,0.1)
border none
outline none
border-radius 2px
margin-right 5px
padding 2px 5px
[id=export-wrap]
height 90px
display flex
justify-content center
margin 20px 0 10px 0
button
outline none
font-size 48px
color #A0A0A0
background-color transparent
border none
margin 0 5px
border-radius 5px
&:hover
transition 0.2s
background-color alpha($ui-button--hover-backgroundColor, 30%)
color $ui-inactive-text-color
p
font-size 13px
color #A0A0A0
font-weight light
&:hover
color $ui-inactive-text-color
.export--enable
cursor pointer
.export--unable
cursor not-allowed
body[data-theme="dark"]
.control-infoButton-panel
background-color $ui-dark-noteList-backgroundColor
border 1px solid $ui-dark-borderColor
.control-infoButton-panel-trash
background-color $ui-dark-noteList-backgroundColor
border 1px solid $ui-dark-borderColor
.group-section-label
color $ui-inactive-text-color
.group-section-control
color $ui-dark-text-color
.group-section-control input
background-color alpha($ui-dark-borderColor, 80%)
color $ui-dark-text-color
[id=export-wrap]
button
color $ui-dark-inactive-text-color
&:hover
background-color alpha($ui-dark-borderColor, 20%)
color $ui-dark-text-color
p
color $ui-dark-inactive-text-color
&:hover
color $ui-dark-text-color

View File

@@ -0,0 +1,70 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl'
const InfoPanelTrashed = ({
storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt
}) => (
<div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}>
<div styleName='group-section'>
<div styleName='group-section-label'>
Storage
</div>
<div styleName='group-section-control'>
{storageName}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Folder
</div>
<div styleName='group-section-control'>
<text>Trash</text>{folderName}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Created
</div>
<div styleName='group-section-control'>
{createdAt}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Updated
</div>
<div styleName='group-section-control'>
{updatedAt}
</div>
</div>
<div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o fa-fw' />
<p>.md</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o fa-fw' />
<p>.txt</p>
</button>
<button styleName='export--unable'>
<i className='fa fa-file-pdf-o fa-fw' />
<p>.pdf</p>
</button>
</div>
</div>
)
InfoPanelTrashed.propTypes = {
storageName: PropTypes.string.isRequired,
folderName: PropTypes.string.isRequired,
updatedAt: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
exportAsMd: PropTypes.func.isRequired,
exportAsTxt: PropTypes.func.isRequired
}
export default CSSModules(InfoPanelTrashed, styles)

View File

@@ -1,27 +0,0 @@
/**
* @fileoverview Component for show updated date of the detail.
*/
import React, { PropTypes } from 'react'
import { getLastUpdated } from 'browser/lib/date-formatter'
import CSSModules from 'browser/lib/CSSModules'
import styles from './LastUpdatedString.styl'
const LastUpdatedString = ({ date }) => {
let text = ''
try {
text = `Last updated at ${getLastUpdated(date)}`
} catch (e) {
text = ''
}
return (
<p styleName='info-right-date'>{text}</p>
)
}
LastUpdatedString.propTypes = {
date: PropTypes.string
}
export default CSSModules(LastUpdatedString, styles)

View File

@@ -1,10 +0,0 @@
.info-right-date
display inline
line-height 24px
padding-right 25px
font-size 11px
color $ui-button-color
body[data-theme="dark"]
.info-right-date
color $ui-dark-button-color

View File

@@ -14,6 +14,12 @@ import StatusBar from '../StatusBar'
import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton'
import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed'
import { formatDate } from 'browser/lib/date-formatter'
import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus'
const electron = require('electron')
const { remote } = electron
@@ -52,7 +58,7 @@ class MarkdownNoteDetail extends React.Component {
note: Object.assign({}, nextProps.note)
}, () => {
this.refs.content.reload()
this.refs.tags.reset()
if (this.refs.tags) this.refs.tags.reset()
})
}
}
@@ -65,29 +71,11 @@ class MarkdownNoteDetail extends React.Component {
ee.off('topbar:togglelockbutton', this.toggleLockButton)
}
getPercentageOfCompleteTodo (noteContent) {
let splitted = noteContent.split('\n')
let numberOfTodo = 0
let numberOfCompletedTodo = 0
splitted.forEach((line) => {
let trimmedLine = line.trim()
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) {
numberOfTodo++
}
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) {
numberOfCompletedTodo++
}
})
return Math.floor(numberOfCompletedTodo / numberOfTodo * 100)
}
handleChange (e) {
let { note } = this.state
note.content = this.refs.content.value
note.tags = this.refs.tags.value
if (this.refs.tags) note.tags = this.refs.tags.value
note.title = markdown.strip(findNoteTitle(note.content))
note.updatedAt = new Date()
@@ -117,7 +105,7 @@ class MarkdownNoteDetail extends React.Component {
type: 'UPDATE_NOTE',
note: note
})
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('EDIT_NOTE')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
})
}
@@ -156,7 +144,7 @@ class MarkdownNoteDetail extends React.Component {
handleStarButtonClick (e) {
let { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_STAR')
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred
@@ -171,14 +159,26 @@ class MarkdownNoteDetail extends React.Component {
}
handleDeleteButtonClick (e) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete a note',
detail: 'This work cannot be undone.',
buttons: ['Confirm', 'Cancel']
})
if (index === 0) {
exportAsMd () {
ee.emit('export:save-md')
}
exportAsTxt () {
ee.emit('export:save-text')
}
handleTrashButtonClick (e) {
let { note } = this.state
const { isTrashed } = note
if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props
dataApi
.deleteNote(note.storage, note.key)
@@ -191,9 +191,31 @@ class MarkdownNoteDetail extends React.Component {
})
}
ee.once('list:moved', dispatchHandler)
ee.emit('list:next')
})
} else {
note.isTrashed = true
this.setState({
note
}, () => {
this.save()
})
}
ee.emit('list:next')
}
handleUndoButtonClick (e) {
let { note } = this.state
note.isTrashed = false
this.setState({
note
}, () => {
this.save()
this.refs.content.reload()
ee.emit('list:next')
})
}
handleFullScreenButton (e) {
@@ -208,7 +230,7 @@ class MarkdownNoteDetail extends React.Component {
}
getToggleLockButton () {
return this.state.isLocked ? 'fa-lock' : 'fa-unlock-alt'
return this.state.isLocked ? 'fa-lock' : 'fa-unlock'
}
handleDeleteKeyDown (e) {
@@ -228,76 +250,120 @@ class MarkdownNoteDetail extends React.Component {
this.focus()
}
handleInfoButtonClick (e) {
const infoPanel = document.querySelector('.infoPanel')
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
}
render () {
let { data, config } = this.props
let { data, config, location } = this.props
let { note } = this.state
let storageKey = note.storage
let folderKey = note.folder
let options = []
data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => {
options.push({
storage: storage,
folder: folder
})
})
})
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const trashTopBar = <div styleName='info'>
<div styleName='info-left'>
<i styleName='undo-button'
className='fa fa-undo fa-fw'
onClick={(e) => this.handleUndoButtonClick(e)}
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanelTrashed
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}
updatedAt={formatDate(note.updatedAt)}
createdAt={formatDate(note.createdAt)}
exportAsMd={this.exportAsMd}
exportAsTxt={this.exportAsTxt}
/>
</div>
</div>
const detailTopBar = <div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
ref='folder'
data={data}
onChange={(e) => this.handleFolderChange(e)}
/>
</div>
<TagSelect
ref='tags'
value={this.state.note.tags}
onChange={(e) => this.handleChange(e)}
/>
<TodoListPercentage
percentageOfTodo={getTodoPercentageOfCompleted(note.content)}
/>
</div>
<div styleName='info-right'>
{(() => {
const faClassName = `fa ${this.getToggleLockButton()}`
const lockButtonComponent =
<button styleName='control-lockButton'
onFocus={(e) => this.handleFocus(e)}
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
>
<i className={faClassName} styleName='lock-button' />
<span styleName='control-lockButton-tooltip'>
{this.state.isLocked ? 'Unlock' : 'Lock'}
</span>
</button>
return (
this.state.isLockButtonShown ? lockButtonComponent : ''
)
})()}
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-expand' styleName='fullScreen-button' />
</button>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}
noteLink={`[${note.title}](${location.query.key})`}
updatedAt={formatDate(note.updatedAt)}
createdAt={formatDate(note.createdAt)}
exportAsMd={this.exportAsMd}
exportAsTxt={this.exportAsTxt}
/>
</div>
</div>
return (
<div className='NoteDetail'
style={this.props.style}
styleName='root'
>
<div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
ref='folder'
data={data}
onChange={(e) => this.handleFolderChange(e)}
/>
</div>
<TagSelect
ref='tags'
value={this.state.note.tags}
onChange={(e) => this.handleChange(e)}
/>
<TodoListPercentage
percentageOfTodo={this.getPercentageOfCompleteTodo(note.content)}
/>
</div>
<div styleName='info-right'>
{(() => {
const faClassName = `fa ${this.getToggleLockButton()}`
const lockButtonComponent =
<button styleName='control-lockButton'
onFocus={(e) => this.handleFocus(e)}
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
>
<i className={faClassName} styleName='lock-button' />
<span styleName='control-lockButton-tooltip'>
{this.state.isLocked ? 'Unlock' : 'Lock'}
</span>
</button>
return (
this.state.isLockButtonShown ? lockButtonComponent : ''
)
})()}
<button styleName='control-trashButton'
onClick={(e) => this.handleDeleteButtonClick(e)}
>
<svg height='14px' id='Capa_1' style={{enableBackground: 'new 0 0 753.23 753.23'}} width='14px' version='1.1' viewBox='0 0 753.23 753.23' x='0px' y='0px' xmlSpace='preserve'>
<g>
<g id='_x34__19_'>
<g>
<path d='M494.308,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077c0-12.993-10.545-23.539-23.538-23.539&#xA;&#x9;&#x9;&#x9;&#x9;s-23.538,10.545-23.538,23.539v282.461C470.77,648.531,481.314,659.077,494.308,659.077z M635.538,94.154h-141.23V47.077&#xA;&#x9;&#x9;&#x9;&#x9;C494.308,21.067,473.24,0,447.23,0H306c-26.01,0-47.077,21.067-47.077,47.077v47.077h-141.23&#xA;&#x9;&#x9;&#x9;&#x9;c-26.01,0-47.077,21.067-47.077,47.077v47.077c0,25.986,21.067,47.077,47.077,47.077v423.692&#xA;&#x9;&#x9;&#x9;&#x9;c0,51.996,42.157,94.153,94.154,94.153h329.539c51.996,0,94.153-42.157,94.153-94.153V235.385&#xA;&#x9;&#x9;&#x9;&#x9;c26.01,0,47.077-21.091,47.077-47.077V141.23C682.615,115.221,661.548,94.154,635.538,94.154z M306,70.615&#xA;&#x9;&#x9;&#x9;&#x9;c0-12.993,10.545-23.539,23.538-23.539h94.154c12.993,0,23.538,10.545,23.538,23.539v23.539c-22.809,0-141.23,0-141.23,0V70.615z&#xA;&#x9;&#x9;&#x9;&#x9; M588.461,659.077c0,25.986-21.066,47.076-47.076,47.076H211.846c-26.01,0-47.077-21.09-47.077-47.076V235.385h423.692V659.077z&#xA;&#x9;&#x9;&#x9;&#x9; M612,188.308H141.23c-12.993,0-23.538-10.545-23.538-23.539s10.545-23.539,23.538-23.539H612&#xA;&#x9;&#x9;&#x9;&#x9;c12.993,0,23.538,10.545,23.538,23.539S624.993,188.308,612,188.308z M258.923,659.077c12.993,0,23.539-10.546,23.539-23.539&#xA;&#x9;&#x9;&#x9;&#x9;V353.077c0-12.993-10.545-23.539-23.539-23.539s-23.539,10.545-23.539,23.539v282.461&#xA;&#x9;&#x9;&#x9;&#x9;C235.384,648.531,245.93,659.077,258.923,659.077z M376.615,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077&#xA;&#x9;&#x9;&#x9;&#x9;c0-12.993-10.545-23.539-23.538-23.539s-23.539,10.545-23.539,23.539v282.461C353.077,648.531,363.622,659.077,376.615,659.077z' />
</g>
</g>
</g>
</svg>
</button>
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-arrows-alt' styleName='fullScreen-button' />
</button>
</div>
</div>
{location.pathname === '/trashed' ? trashTopBar : detailTopBar}
<div styleName='body'>
<MarkdownEditor

View File

@@ -27,13 +27,9 @@
opacity 0
transition 0.1s
.control-trashButton
float right
topBarButtonLight()
.control-fullScreenButton
float right
padding 7px
padding 0 0 2px 0
topBarButtonLight()
.body
@@ -58,8 +54,5 @@ body[data-theme="dark"]
.control-lockButton-tooltip
darkTooltip()
.control-trashButton
topBarButtonDark()
.control-fullScreenButton
topBarButtonDark()

View File

@@ -15,26 +15,26 @@ $info-margin-under-border = 27px
float left
padding 0 5px
margin 0px 2px
.info-left-top
display inline-block
height $info-height
line-height $info-height
.info-left-top-folderSelect
display inline-block
padding 0 3px
height 34px
line-height 34px
vertical-align middle
line-height 26px
display flex
align-items center
justify-content center
border-radius 3px
.info-left-button
width 34px
height 34px
navButtonColor()
color $ui-favorite-star-button-color
font-size 14px
line-height 0
margin 13px 2px
padding 0
border-radius 17px
@@ -44,7 +44,7 @@ $info-margin-under-border = 27px
border-color $ui-favorite-star-button-color
&:active, &:active:hover
background-color $ui-favorite-star-button-color
color $ui-button--active-color
color $ui-button--color
.info-right
position absolute
@@ -54,6 +54,27 @@ $info-margin-under-border = 27px
bottom 1px
padding-left 30px
.undo-button
width 34px
height 34px
border-radius 17px
font-size 14px
margin 15px 7px
border none
color $ui-button-color
display flex
align-items center
justify-content center
fill $ui-button-color
background-color transparent
cursor pointer
&:active
border-color $ui-button--active-backgroundColor
&:hover
background-color alpha($ui-button--hover-backgroundColor, 60%)
.control-lockButton-tooltip
opacity 1
body[data-theme="dark"]
.info
border-color $ui-dark-borderColor
@@ -73,3 +94,6 @@ body[data-theme="dark"]
.info-right
background-color $ui-dark-noteDetail-backgroundColor
.undo-button
topBarButtonDark()

View File

@@ -17,6 +17,11 @@ import ConfigManager from 'browser/main/lib/ConfigManager'
import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton'
import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed'
import { formatDate } from 'browser/lib/date-formatter'
function pass (name) {
switch (name) {
@@ -53,7 +58,7 @@ class SnippetNoteDetail extends React.Component {
}
componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key) {
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
if (this.saveQueue != null) this.saveNow()
let nextNote = Object.assign({
description: ''
@@ -68,7 +73,7 @@ class SnippetNoteDetail extends React.Component {
snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload()
})
this.refs.tags.reset()
if (this.refs.tags) this.refs.tags.reset()
})
}
}
@@ -80,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
handleChange (e) {
let { note } = this.state
note.tags = this.refs.tags.value
if (this.refs.tags) note.tags = this.refs.tags.value
note.description = this.refs.description.value
note.updatedAt = new Date()
note.title = findNoteTitle(note.description)
@@ -111,7 +116,7 @@ class SnippetNoteDetail extends React.Component {
type: 'UPDATE_NOTE',
note: note
})
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('EDIT_NOTE')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
})
}
@@ -150,7 +155,7 @@ class SnippetNoteDetail extends React.Component {
handleStarButtonClick (e) {
let { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_STAR')
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred
@@ -165,14 +170,18 @@ class SnippetNoteDetail extends React.Component {
}
handleDeleteButtonClick (e) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete a note',
detail: 'This work cannot be undone.',
buttons: ['Confirm', 'Cancel']
})
if (index === 0) {
handleTrashButtonClick (e) {
let { note } = this.state
const { isTrashed } = note
if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props
dataApi
.deleteNote(note.storage, note.key)
@@ -185,9 +194,30 @@ class SnippetNoteDetail extends React.Component {
})
}
ee.once('list:moved', dispatchHandler)
ee.emit('list:next')
})
} else {
note.isTrashed = true
this.setState({
note
}, () => {
this.save()
})
}
ee.emit('list:next')
}
handleUndoButtonClick (e) {
let { note } = this.state
note.isTrashed = false
this.setState({
note
}, () => {
this.save()
ee.emit('list:next')
})
}
handleFullScreenButton (e) {
@@ -432,10 +462,27 @@ class SnippetNoteDetail extends React.Component {
this.refs['code-' + this.state.snippetIndex].focus()
}
handleInfoButtonClick (e) {
const infoPanel = document.querySelector('.infoPanel')
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
}
showWarning () {
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Sorry!',
detail: 'md/text import is available only a markdown note.',
buttons: ['OK']
})
}
render () {
let { data, config } = this.props
let { data, config, location } = this.props
let { note } = this.state
let storageKey = note.storage
let folderKey = note.folder
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
@@ -473,6 +520,7 @@ class SnippetNoteDetail extends React.Component {
onChange={(e) => this.handleCodeChange(index)(e)}
ref={'code-' + index}
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
storageKey={storageKey}
/>
: <CodeEditor styleName='tabView-content'
mode={snippet.mode}
@@ -490,54 +538,90 @@ class SnippetNoteDetail extends React.Component {
</div>
})
let options = []
data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => {
options.push({
storage: storage,
folder: folder
})
})
})
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const trashTopBar = <div styleName='info'>
<div styleName='info-left'>
<i styleName='undo-button'
className='fa fa-undo fa-fw'
onClick={(e) => this.handleUndoButtonClick(e)}
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanelTrashed
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}
updatedAt={formatDate(note.updatedAt)}
createdAt={formatDate(note.createdAt)}
exportAsMd={this.showWarning}
exportAsTxt={this.showWarning}
/>
</div>
</div>
const detailTopBar = <div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
ref='folder'
data={data}
onChange={(e) => this.handleFolderChange(e)}
/>
</div>
<TagSelect
ref='tags'
value={this.state.note.tags}
onChange={(e) => this.handleChange(e)}
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-expand' styleName='fullScreen-button' />
</button>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}
noteLink={`[${note.title}](${location.query.key})`}
updatedAt={formatDate(note.updatedAt)}
createdAt={formatDate(note.createdAt)}
exportAsMd={this.showWarning}
exportAsTxt={this.showWarning}
/>
</div>
</div>
return (
<div className='NoteDetail'
style={this.props.style}
styleName='root'
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
ref='folder'
data={data}
onChange={(e) => this.handleFolderChange(e)}
/>
</div>
<TagSelect
ref='tags'
value={this.state.note.tags}
onChange={(e) => this.handleChange(e)}
/>
</div>
<div styleName='info-right'>
<button styleName='control-trashButton'
onClick={(e) => this.handleDeleteButtonClick(e)}
>
<svg height='14px' id='Capa_1' style={{enableBackground: 'new 0 0 753.23 753.23'}} width='14px' version='1.1' viewBox='0 0 753.23 753.23' x='0px' y='0px' xmlSpace='preserve'>
<g>
<g id='_x34__19_'>
<g>
<path d='M494.308,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077c0-12.993-10.545-23.539-23.538-23.539&#xA;&#x9;&#x9;&#x9;&#x9;s-23.538,10.545-23.538,23.539v282.461C470.77,648.531,481.314,659.077,494.308,659.077z M635.538,94.154h-141.23V47.077&#xA;&#x9;&#x9;&#x9;&#x9;C494.308,21.067,473.24,0,447.23,0H306c-26.01,0-47.077,21.067-47.077,47.077v47.077h-141.23&#xA;&#x9;&#x9;&#x9;&#x9;c-26.01,0-47.077,21.067-47.077,47.077v47.077c0,25.986,21.067,47.077,47.077,47.077v423.692&#xA;&#x9;&#x9;&#x9;&#x9;c0,51.996,42.157,94.153,94.154,94.153h329.539c51.996,0,94.153-42.157,94.153-94.153V235.385&#xA;&#x9;&#x9;&#x9;&#x9;c26.01,0,47.077-21.091,47.077-47.077V141.23C682.615,115.221,661.548,94.154,635.538,94.154z M306,70.615&#xA;&#x9;&#x9;&#x9;&#x9;c0-12.993,10.545-23.539,23.538-23.539h94.154c12.993,0,23.538,10.545,23.538,23.539v23.539c-22.809,0-141.23,0-141.23,0V70.615z&#xA;&#x9;&#x9;&#x9;&#x9; M588.461,659.077c0,25.986-21.066,47.076-47.076,47.076H211.846c-26.01,0-47.077-21.09-47.077-47.076V235.385h423.692V659.077z&#xA;&#x9;&#x9;&#x9;&#x9; M612,188.308H141.23c-12.993,0-23.538-10.545-23.538-23.539s10.545-23.539,23.538-23.539H612&#xA;&#x9;&#x9;&#x9;&#x9;c12.993,0,23.538,10.545,23.538,23.539S624.993,188.308,612,188.308z M258.923,659.077c12.993,0,23.539-10.546,23.539-23.539&#xA;&#x9;&#x9;&#x9;&#x9;V353.077c0-12.993-10.545-23.539-23.539-23.539s-23.539,10.545-23.539,23.539v282.461&#xA;&#x9;&#x9;&#x9;&#x9;C235.384,648.531,245.93,659.077,258.923,659.077z M376.615,659.077c12.993,0,23.538-10.546,23.538-23.539V353.077&#xA;&#x9;&#x9;&#x9;&#x9;c0-12.993-10.545-23.539-23.538-23.539s-23.539,10.545-23.539,23.539v282.461C353.077,648.531,363.622,659.077,376.615,659.077z' />
</g>
</g>
</g>
</svg>
</button>
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-arrows-alt' styleName='fullScreen-button' />
</button>
</div>
</div>
{location.pathname === '/trashed' ? trashTopBar : detailTopBar}
<div styleName='body'>
<div styleName='description'>

View File

@@ -66,13 +66,9 @@
&:active .update-icon
color white
.control-trashButton
float right
topBarButtonLight()
.control-fullScreenButton
float right
padding 7px
padding 0 0 2px 0
topBarButtonLight()
body[data-theme="dark"]
@@ -105,8 +101,5 @@ body[data-theme="dark"]
transition 0.15s
color $ui-dark-text-color
.control-trashButton
topBarButtonDark()
.control-fullScreenButton
topBarButtonDark()

View File

@@ -57,7 +57,7 @@ class TagSelect extends React.Component {
}
submitTag () {
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_TAG')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
let { value } = this.props
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')

View File

@@ -1,7 +1,7 @@
.root
display inline-block
top 19px
user-select none
height 23px
vertical-align middle
width 300px
overflow-x scroll
@@ -14,7 +14,6 @@
display inline-block
margin 1px 3px
padding 0
vertical-align middle
height 20px
background-color alpha($ui-tag-backgroundColor, 10%)
border-radius 3px
@@ -49,9 +48,9 @@
.newTag
display inline-block
margin 0 2px
margin 2px 0 15px 2px
vertical-align middle
height 24px
height 18px
box-sizing borde-box
border none
background-color transparent

View File

@@ -0,0 +1,19 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './TrashButton.styl'
const TrashButton = ({
onClick
}) => (
<button styleName='control-trashButton'
onClick={(e) => onClick(e)}
>
<i className='fa fa-trash trashButton' styleName='info-button' />
</button>
)
TrashButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(TrashButton, styles)

View File

@@ -0,0 +1,11 @@
.control-trashButton
float right
topBarButtonLight()
.trashButton
padding 0px
margin 15px 0
body[data-theme="dark"]
.control-trashButton
topBarButtonDark()

View File

@@ -17,7 +17,7 @@ class Detail extends React.Component {
this.refs.root != null && this.refs.root.focus()
}
this.deleteHandler = () => {
this.refs.root != null && this.refs.root.handleDeleteButtonClick()
this.refs.root != null && this.refs.root.handleTrashButtonClick()
}
}
@@ -49,7 +49,7 @@ class Detail extends React.Component {
tabIndex='0'
>
<div styleName='empty'>
<div styleName='empty-message'>{OSX ? 'Command(⌘)' : 'Ctrl(^)'} + N<br />to create a new post</div>
<div styleName='empty-message'>{OSX ? 'Command(⌘)' : 'Ctrl(^)'} + N<br />to create a new note</div>
</div>
<StatusBar
{..._.pick(this.props, ['config', 'location', 'dispatch'])}

View File

@@ -17,7 +17,7 @@ $control-height = 30px
.control-sortBy
flex 1
padding-left 25px
padding-left 22px
.control-sortBy-select
appearance: none;
@@ -28,11 +28,14 @@ $control-height = 30px
background-color transparent
outline none
cursor pointer
font-size 10px
font-size 11px
&:hover
transition 0.2s
color $ui-text-color
.control-button-area
margin-right 12px
.control-button
width 25px
padding 0

View File

@@ -47,10 +47,7 @@ class NoteList extends React.Component {
this.alertIfSnippet()
}
this.importFromFileHandler = this.importFromFile.bind(this)
this.jumpToTopHandler = () => {
this.jumpToTop()
}
this.jumpNoteByHash = this.jumpNoteByHashHandler.bind(this)
this.state = {
}
@@ -62,9 +59,8 @@ class NoteList extends React.Component {
ee.on('list:prior', this.selectPriorNoteHandler)
ee.on('list:focus', this.focusHandler)
ee.on('list:isMarkdownNote', this.alertIfSnippetHandler)
ee.on('list:top', this.jumpToTopHandler)
ee.on('list:jumpToTop', this.jumpToTopHandler)
ee.on('import:file', this.importFromFileHandler)
ee.on('list:jump', this.jumpNoteByHash)
}
componentWillReceiveProps (nextProps) {
@@ -84,9 +80,8 @@ class NoteList extends React.Component {
ee.off('list:prior', this.selectPriorNoteHandler)
ee.off('list:focus', this.focusHandler)
ee.off('list:isMarkdownNote', this.alertIfSnippetHandler)
ee.off('list:top', this.jumpToTopHandler)
ee.off('list:jumpToTop', this.jumpToTopHandler)
ee.off('import:file', this.importFromFileHandler)
ee.off('list:jump', this.jumpNoteByHash)
}
componentDidUpdate (prevProps) {
@@ -179,6 +174,31 @@ class NoteList extends React.Component {
ee.emit('list:moved')
}
jumpNoteByHashHandler (event, noteHash) {
// first argument event isn't used.
if (this.notes === null || this.notes.length === 0) {
return
}
const { router } = this.context
const { location } = this.props
let targetIndex = _.findIndex(this.notes, (note) => {
return note.storage + '-' + note.key === noteHash
})
if (targetIndex < 0) targetIndex = 0
router.push({
pathname: location.pathname,
query: {
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
}
})
ee.emit('list:moved')
}
handleNoteListKeyDown (e) {
if (e.metaKey || e.ctrlKey) return true
@@ -226,7 +246,12 @@ class NoteList extends React.Component {
if (searchInputText === '') {
router.push('/home')
}
return searchFromNotes(this.props.data, searchInputText)
return searchFromNotes(this.notes, searchInputText)
}
if (location.pathname.match(/\/trashed/)) {
return data.trashedSet.toJS()
.map((uniqueKey) => data.noteMap.get(uniqueKey))
}
let storageKey = params.storageKey
@@ -264,49 +289,6 @@ class NoteList extends React.Component {
})
}
handleNoteContextMenu (e, uniqueKey) {
let menu = new Menu()
menu.append(new MenuItem({
label: 'Delete Note',
click: (e) => this.handleDeleteNote(e, uniqueKey)
}))
menu.popup()
}
handleDeleteNote (e, uniqueKey) {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete a note',
detail: 'This work cannot be undone.',
buttons: ['Confirm', 'Cancel']
})
if (index === 0) {
let { dispatch, location } = this.props
let splitted = uniqueKey.split('-')
let storageKey = splitted.shift()
let noteKey = splitted.shift()
dataApi
.deleteNote(storageKey, noteKey)
.then((data) => {
let dispatchHandler = () => {
dispatch({
type: 'DELETE_NOTE',
storageKey: data.storageKey,
noteKey: data.noteKey
})
}
if (location.query.key === uniqueKey) {
ee.once('list:moved', dispatchHandler)
ee.emit('list:next')
} else {
dispatchHandler()
}
})
}
}
handleSortByChange (e) {
let { dispatch } = this.props
@@ -350,23 +332,6 @@ class NoteList extends React.Component {
}
}
jumpToTop () {
if (this.notes === null || this.notes.length === 0) {
return
}
let { router } = this.context
let { location } = this.props
const targetIndex = 0
router.push({
pathname: location.pathname,
query: {
key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
}
})
}
handleDragStart (e, note) {
const noteData = JSON.stringify(note)
e.dataTransfer.setData('note', noteData)
@@ -426,6 +391,10 @@ class NoteList extends React.Component {
: sortByUpdatedAt
this.notes = notes = this.getNotes()
.sort(sortFunc)
.filter((note) => {
// this is for the trash box
if (note.isTrashed !== true || location.pathname === '/trashed') return true
})
let noteList = notes
.map(note => {
@@ -449,7 +418,6 @@ class NoteList extends React.Component {
dateDisplay={dateDisplay}
key={key}
handleNoteClick={this.handleNoteClick.bind(this)}
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleDragStart={this.handleDragStart.bind(this)}
/>
)
@@ -461,7 +429,6 @@ class NoteList extends React.Component {
note={note}
key={key}
handleNoteClick={this.handleNoteClick.bind(this)}
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleDragStart={this.handleDragStart.bind(this)}
/>
)
@@ -479,27 +446,29 @@ class NoteList extends React.Component {
value={config.sortBy}
onChange={(e) => this.handleSortByChange(e)}
>
<option value='UPDATED_AT'>Updated Time</option>
<option value='CREATED_AT'>Created Time</option>
<option value='ALPHABETICAL'>Alphabetical</option>
<option value='UPDATED_AT'>Last Updated</option>
<option value='CREATED_AT'>Creation Time</option>
<option value='ALPHABETICAL'>Alphabetically</option>
</select>
</div>
<button styleName={config.listStyle === 'DEFAULT'
? 'control-button--active'
: 'control-button'
}
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
>
<i className='fa fa-th-large' />
</button>
<button styleName={config.listStyle === 'SMALL'
? 'control-button--active'
: 'control-button'
}
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
>
<i className='fa fa-list-ul' />
</button>
<div styleName='control-button-area'>
<button styleName={config.listStyle === 'DEFAULT'
? 'control-button--active'
: 'control-button'
}
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
>
<i className='fa fa-th-large' />
</button>
<button styleName={config.listStyle === 'SMALL'
? 'control-button--active'
: 'control-button'
}
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
>
<i className='fa fa-list-ul' />
</button>
</div>
</div>
<div styleName='list'
ref='list'

View File

@@ -114,7 +114,7 @@ class StorageItem extends React.Component {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete Folder',
detail: 'This work will deletes all notes in the folder and can not be undone.',
detail: 'This will delete all notes in the folder and can not be undone.',
buttons: ['Confirm', 'Cancel']
})
@@ -180,14 +180,20 @@ class StorageItem extends React.Component {
render () {
let { storage, location, isFolded, data, dispatch } = this.props
let { folderNoteMap } = data
let { folderNoteMap, trashedSet } = data
let folderList = storage.folders.map((folder) => {
let isActive = !!(location.pathname.match(new RegExp('\/storages\/' + storage.key + '\/folders\/' + folder.key)))
let noteSet = folderNoteMap.get(storage.key + '-' + folder.key)
let noteCount = noteSet != null
? noteSet.size
: 0
let noteCount = 0
if (noteSet) {
let trashedNoteCount = 0
const noteKeys = noteSet.map(noteKey => { return noteKey })
trashedSet.toJS().forEach(trashedKey => {
if (noteKeys.some(noteKey => { return noteKey === trashedKey })) trashedNoteCount++
})
noteCount = noteSet.size - trashedNoteCount
}
return (
<StorageItemChild
key={folder.key}

View File

@@ -1,6 +1,7 @@
.root
width 100%
user-select none
padding-top 20px
.header
position relative

View File

@@ -33,12 +33,18 @@ class SideNav extends React.Component {
})
}
handleTrashedButtonClick (e) {
let { router } = this.context
router.push('/trashed')
}
render () {
let { data, location, config, dispatch } = this.props
let isFolded = config.isSideNavFolded
let isHomeActive = !!location.pathname.match(/^\/home$/)
let isStarredActive = !!location.pathname.match(/^\/starred$/)
let isTrashedActive = !!location.pathname.match(/^\/trashed$/)
let storageList = data.storageMap.map((storage, key) => {
return <StorageItem
@@ -62,8 +68,8 @@ class SideNav extends React.Component {
<button styleName='top-menu'
onClick={(e) => this.handleMenuButtonClick(e)}
>
<i className='fa fa-navicon fa-fw' />
<span styleName='top-menu-label'>Menu</span>
<i className='fa fa-wrench fa-fw' />
<span styleName='top-menu-label'>Preferences</span>
</button>
</div>
@@ -72,7 +78,9 @@ class SideNav extends React.Component {
isHomeActive={isHomeActive}
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
isStarredActive={isStarredActive}
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
/>
<div styleName='storageList'>

View File

@@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './StatusBar.styl'
import ZoomManager from 'browser/main/lib/ZoomManager'
import LastUpdatedString from '../Detail/LastUpdatedString'
const electron = require('electron')
const { remote, ipcRenderer } = electron
@@ -68,8 +67,6 @@ class StatusBar extends React.Component {
</button>
: null
}
<LastUpdatedString date={this.props.date} />
</div>
)
}

View File

@@ -19,26 +19,25 @@ $control-height = 34px
.control-search
height 32px
width 1px
flex 1
background-color white
position relative
.control-search-icon
absolute top bottom left
line-height 32px
width 35px
color $ui-inactive-text-color
background-color $ui-noteList-backgroundColor
.control-search-input
display block
absolute top bottom right
left 30px
width 100%
padding-left 12px
background-color $ui-noteList-backgroundColor
input
width 100%
height 100%
outline none
border none
color $ui-text-color
font-size 16px
padding-bottom 2px
background-color $ui-noteList-backgroundColor
.control-search-optionList
@@ -92,9 +91,7 @@ $control-height = 34px
width 32px
height $control-height - 2
navButtonColor()
border $ui-border
border-radius 32px
font-size 14px
font-size 16px
line-height 28px
padding 0
&:active
@@ -132,6 +129,7 @@ body[data-theme="dark"]
background-color $ui-dark-noteList-backgroundColor
.control-search-input
background-color $ui-dark-noteList-backgroundColor
input
background-color $ui-dark-noteList-backgroundColor
color $ui-dark-text-color

View File

@@ -9,6 +9,9 @@ import ee from 'browser/main/lib/eventEmitter'
import ConfigManager from 'browser/main/lib/ConfigManager'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron')
const { dialog } = remote
const OSX = window.process.platform === 'darwin'
class TopBar extends React.Component {
@@ -41,7 +44,17 @@ class TopBar extends React.Component {
}
handleNewPostButtonClick (e) {
let { config } = this.props
let { config, location } = this.props
if (location.pathname === '/trashed') {
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Cannot create new note',
detail: 'You cannot create new note in trash box.',
buttons: ['OK']
})
return
}
switch (config.ui.defaultNote) {
case 'MARKDOWN_NOTE':
@@ -205,7 +218,6 @@ class TopBar extends React.Component {
>
<div styleName='control'>
<div styleName='control-search'>
<i styleName='control-search-icon' className='fa fa-search fa-fw' />
<div styleName='control-search-input'
onFocus={(e) => this.handleSearchFocus(e)}
onBlur={(e) => this.handleSearchBlur(e)}
@@ -232,7 +244,7 @@ class TopBar extends React.Component {
</div>
<button styleName='control-newPostButton'
onClick={(e) => this.handleNewPostButtonClick(e)}>
<i className='fa fa-plus' />
<i className='fa fa-pencil-square-o' />
<span styleName='control-newPostButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n
</span>

View File

@@ -23,6 +23,16 @@ document.addEventListener('dragover', function (e) {
e.stopPropagation()
})
document.addEventListener('click', function (e) {
const className = e.target.className
if (!className && typeof (className) !== 'string') return
const isInfoButton = className.includes('infoButton')
const isInfoPanel = e.target.offsetParent.className.includes('infoPanel')
if (isInfoButton || isInfoPanel) return
const infoPanel = document.querySelector('.infoPanel')
if (infoPanel) infoPanel.style.display = 'none'
})
let el = document.getElementById('content')
const history = syncHistoryWithStore(hashHistory, store)
@@ -51,6 +61,7 @@ ReactDOM.render((
<Route path='home' />
<Route path='starred' />
<Route path='searched' />
<Route path='trashed' />
<Route path='storages'>
<IndexRedirect to='/home' />
<Route path=':storageKey'>

View File

@@ -3,16 +3,18 @@ const AMA = require('aws-sdk-mobile-analytics')
const ConfigManager = require('browser/main/lib/ConfigManager')
AWS.config.region = 'us-east-1'
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
})
const mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appTitle: 'xxxxxxxxxx'
})
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
})
const mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appTitle: 'xxxxxxxxxx'
})
}
function initAwsMobileAnalytics () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
AWS.config.credentials.get((err) => {
if (!err) {
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
@@ -21,11 +23,13 @@ function initAwsMobileAnalytics () {
recordStaticCustomEvent()
}
function recordDynamitCustomEvent (type) {
function recordDynamicCustomEvent (type) {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
mobileAnalyticsClient.recordEvent(type)
}
function recordStaticCustomEvent () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
uiColorTheme: ConfigManager.default.get().ui.theme
})
@@ -33,5 +37,5 @@ function recordStaticCustomEvent () {
module.exports = {
initAwsMobileAnalytics,
recordDynamitCustomEvent
recordDynamicCustomEvent
}

View File

@@ -1,9 +1,13 @@
import _ from 'lodash'
import RcParser from 'browser/lib/RcParser'
const OSX = global.process.platform === 'darwin'
const win = global.process.platform === 'win32'
const electron = require('electron')
const { ipcRenderer } = electron
const consts = require('browser/lib/consts')
const path = require('path')
const fs = require('fs')
let isInitialized = false
@@ -14,6 +18,7 @@ export const DEFAULT_CONFIG = {
navWidth: 200,
sortBy: 'UPDATED_AT', // 'CREATED_AT', 'UPDATED_AT', 'APLHABETICAL'
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
amaEnabled: true,
hotkey: {
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
@@ -24,18 +29,18 @@ export const DEFAULT_CONFIG = {
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
},
editor: {
theme: 'default',
theme: 'base16-light',
keyMap: 'sublime',
fontSize: '14',
fontFamily: 'Monaco, Consolas',
fontFamily: win ? 'Segoe UI' : 'Monaco, Consolas',
indentType: 'space',
indentSize: '2',
switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR
},
preview: {
fontSize: '14',
fontFamily: 'Lato',
codeBlockTheme: 'elegant',
fontFamily: win ? 'Segoe UI' : 'Lato',
codeBlockTheme: 'dracula',
lineNumber: true
}
}
@@ -55,17 +60,17 @@ function _save (config) {
}
function get () {
let config = window.localStorage.getItem('config')
const rawStoredConfig = window.localStorage.getItem('config')
const storedConfig = Object.assign({}, DEFAULT_CONFIG, JSON.parse(rawStoredConfig))
let config = storedConfig
try {
config = Object.assign({}, DEFAULT_CONFIG, JSON.parse(config))
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, config.hotkey)
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, config.ui)
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, config.editor)
config.preview = Object.assign({}, DEFAULT_CONFIG.preview, config.preview)
const boostnotercConfig = RcParser.parse()
config = assignConfigValues(storedConfig, boostnotercConfig)
if (!validate(config)) throw new Error('INVALID CONFIG')
} catch (err) {
console.warn('Boostnote resets the malformed configuration.')
console.warn('Boostnote resets the invalid configuration.')
config = DEFAULT_CONFIG
_save(config)
}
@@ -124,6 +129,15 @@ function set (updates) {
})
}
function assignConfigValues (originalConfig, rcConfig) {
let config = Object.assign({}, DEFAULT_CONFIG, originalConfig, rcConfig)
config.hotkey = Object.assign({}, DEFAULT_CONFIG.hotkey, originalConfig.hotkey, rcConfig.hotkey)
config.ui = Object.assign({}, DEFAULT_CONFIG.ui, originalConfig.ui, rcConfig.ui)
config.editor = Object.assign({}, DEFAULT_CONFIG.editor, originalConfig.editor, rcConfig.editor)
config.preview = Object.assign({}, DEFAULT_CONFIG.preview, originalConfig.preview, rcConfig.preview)
return config
}
export default {
get,
set,

View File

@@ -2,6 +2,7 @@ const fs = require('fs')
const path = require('path')
const _ = require('lodash')
const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage')
/**
* @description To copy an image and return the path.
@@ -12,17 +13,17 @@ const sander = require('sander')
function copyImage (filePath, storageKey) {
return new Promise((resolve, reject) => {
try {
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
const storage = _.find(cachedStorageList, {key: storageKey})
if (storage === undefined) throw new Error('Target storage doesn\'t exist.')
const targetStorage = storage
const targetStorage = findStorage(storageKey)
const inputImage = fs.createReadStream(filePath)
const imageName = path.basename(filePath)
const outputImage = fs.createWriteStream(path.join(targetStorage.path, 'images', imageName))
const imageExt = path.extname(filePath)
const imageName = Math.random().toString(36).slice(-16)
const basename = `${imageName}${imageExt}`
const imageDir = path.join(targetStorage.path, 'images')
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
const outputImage = fs.createWriteStream(path.join(imageDir, basename))
inputImage.pipe(outputImage)
resolve(`${encodeURI(targetStorage.path)}/images/${encodeURI(imageName)}`)
resolve(basename)
} catch (e) {
return reject(e)
}

View File

@@ -3,6 +3,7 @@ const keygen = require('browser/lib/keygen')
const path = require('path')
const resolveStorageData = require('./resolveStorageData')
const CSON = require('@rokt33r/season')
const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} storageKey
@@ -29,11 +30,7 @@ function createFolder (storageKey, input) {
if (!_.isString(input.name)) throw new Error('Name must be a string.')
if (!_.isString(input.color)) throw new Error('Color must be a string.')
rawStorages = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(rawStorages, {key: storageKey})
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}

View File

@@ -4,12 +4,14 @@ const _ = require('lodash')
const keygen = require('browser/lib/keygen')
const path = require('path')
const CSON = require('@rokt33r/season')
const { findStorage } = require('browser/lib/findStorage')
function validateInput (input) {
if (!_.isArray(input.tags)) input.tags = []
input.tags = input.tags.filter((tag) => _.isString(tag) && tag.trim().length > 0)
if (!_.isString(input.title)) input.title = ''
input.isStarred = !!input.isStarred
input.isTrashed = !!input.isTrashed
switch (input.type) {
case 'MARKDOWN_NOTE':
@@ -37,11 +39,7 @@ function createNote (storageKey, input) {
input = Object.assign({}, input)
validateInput(input)
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(cachedStorageList, {key: storageKey})
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}

View File

@@ -4,6 +4,7 @@ const resolveStorageData = require('./resolveStorageData')
const resolveStorageNotes = require('./resolveStorageNotes')
const CSON = require('@rokt33r/season')
const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} storageKey
@@ -21,11 +22,7 @@ function deleteFolder (storageKey, folderKey) {
let rawStorages
let targetStorage
try {
rawStorages = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(rawStorages, {key: storageKey})
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}

View File

@@ -2,15 +2,12 @@ const resolveStorageData = require('./resolveStorageData')
const _ = require('lodash')
const path = require('path')
const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage')
function deleteNote (storageKey, noteKey) {
let targetStorage
try {
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(cachedStorageList, {key: storageKey})
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}

View File

@@ -4,17 +4,13 @@ const path = require('path')
const CSON = require('@rokt33r/season')
const keygen = require('browser/lib/keygen')
const sander = require('sander')
const { findStorage } = require('browser/lib/findStorage')
function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
let oldStorage, newStorage
try {
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Storage doesn\'t exist.')
oldStorage = _.find(cachedStorageList, {key: storageKey})
if (oldStorage == null) throw new Error('Storage doesn\'t exist.')
newStorage = _.find(cachedStorageList, {key: newStorageKey})
oldStorage = findStorage(storageKey)
newStorage = findStorage(newStorageKey)
if (newStorage == null) throw new Error('Target storage doesn\'t exist.')
} catch (e) {
return Promise.reject(e)

View File

@@ -1,5 +1,7 @@
const _ = require('lodash')
const resolveStorageData = require('./resolveStorageData')
const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} key
* @param {String} name

View File

@@ -2,6 +2,7 @@ const resolveStorageData = require('./resolveStorageData')
const _ = require('lodash')
const path = require('path')
const CSON = require('@rokt33r/season')
const { findStorage } = require('browser/lib/findStorage')
function validateInput (input) {
let validatedInput = {}
@@ -21,6 +22,10 @@ function validateInput (input) {
validatedInput.isStarred = !!input.isStarred
}
if (input.isTrashed != null) {
validatedInput.isTrashed = !!input.isTrashed
}
validatedInput.type = input.type
switch (input.type) {
case 'MARKDOWN_NOTE':
@@ -64,11 +69,7 @@ function updateNote (storageKey, noteKey, input) {
if (input == null) throw new Error('No input found.')
input = validateInput(input)
let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('Target storage doesn\'t exist.')
targetStorage = _.find(cachedStorageList, {key: storageKey})
if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
@@ -101,6 +102,7 @@ function updateNote (storageKey, noteKey, input) {
noteData.createdAt = new Date()
noteData.updatedAt = new Date()
noteData.isStarred = false
noteData.isTrashed = false
noteData.tags = []
}

View File

@@ -49,7 +49,7 @@ class CreateFolderModal extends React.Component {
}
confirm () {
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_FOLDER')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_FOLDER')
if (this.state.name.trim().length > 0) {
let { storage } = this.props
let input = {

View File

@@ -103,7 +103,7 @@ class InitModal extends React.Component {
} else {
return dataApi
.createFolder(data.storage.key, {
color: '#6AA5E9',
color: '#1278BD',
name: 'Default'
})
.then((_data) => {
@@ -122,19 +122,6 @@ class InitModal extends React.Component {
notes: data.notes
})
let defaultMarkdownNote = dataApi
.createNote(data.storage.key, {
type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote :)',
content: '# Welcome to Boostnote :)\nThis is a markdown note.\n\nClick to edit this note.'
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
let defaultSnippetNote = dataApi
.createNote(data.storage.key, {
type: 'SNIPPET_NOTE',
@@ -145,12 +132,12 @@ class InitModal extends React.Component {
{
name: 'example.html',
mode: 'html',
content: '<html>\n<body>\n<h1 id=\'hello\'>Hello World</h1>\n</body>\n</html>'
content: '<html>\n<body>\n<h1 id=\'hello\'>Enjoy Boostnote!</h1>\n</body>\n</html>'
},
{
name: 'example.js',
mode: 'javascript',
content: 'var html = document.getElementById(\'hello\').innerHTML\n\nconsole.log(html)'
content: 'var boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)'
}
]
})
@@ -160,6 +147,19 @@ class InitModal extends React.Component {
note: note
})
})
let defaultMarkdownNote = dataApi
.createNote(data.storage.key, {
type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote!',
content: '# Welcome to Boostnote! \n### _Click to edit this note._\n\n---\n\nBoostnote is an *open source* note-taking app. \nRepository is published on [GitHub](https://github.com/BoostIO/Boostnote), and tweeting everyday on [@Boostnoteapp](https://twitter.com/boostnoteapp)!\n\n## Features \n- [x] No Internet and Registration Required. \n- [ ] Quick search and copy the content of note. `macOS: Cmd + Alt + S / windows: Ctrl + Alt + S` \n- [ ] Markdown & Snippet note. \n- [ ] Available for `vim` and `emacs` mode. \n- [ ] Choose your favorite theme on UI, Editor and Code Block! \n--- \n\n- Copy Codeblock on Markdown Preview.\n```javascript\nvar boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)\n```'
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
return Promise.resolve(defaultSnippetNote)
.then(defaultMarkdownNote)

View File

@@ -24,8 +24,8 @@ class NewNoteModal extends React.Component {
}
handleMarkdownNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_MARKDOWN')
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_ALLNOTE')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props
dataApi
.createNote(storage, {
@@ -56,8 +56,8 @@ class NewNoteModal extends React.Component {
}
handleSnippetNoteButtonClick (e) {
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_SNIPPET')
AwsMobileAnalyticsConfig.recordDynamitCustomEvent('ADD_ALLNOTE')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET')
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
let { storage, folder, dispatch, location } = this.props
dataApi

View File

@@ -1,6 +1,9 @@
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager'
import store from 'browser/main/store'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
const electron = require('electron')
const { shell, remote } = electron
@@ -11,6 +14,7 @@ class InfoTab extends React.Component {
super(props)
this.state = {
config: this.props.config
}
}
@@ -19,6 +23,29 @@ class InfoTab extends React.Component {
e.preventDefault()
}
handleConfigChange (e) {
const newConfig = { amaEnabled: this.refs.amaEnabled.checked }
this.setState({ config: newConfig })
}
handleSaveButtonClick (e) {
let newConfig = {
amaEnabled: this.state.config.amaEnabled
}
if (!newConfig.amaEnabled) {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
}
ConfigManager.set(newConfig)
store.dispatch({
type: 'SET_CONFIG',
config: newConfig
})
}
render () {
return (
<div styleName='root'>
@@ -68,6 +95,18 @@ class InfoTab extends React.Component {
License: GPL v3
</li>
</ul>
<hr />
<div styleName='policy'>Data collection policy</div>
<p>We collect only the number of DAU for Boostnote and DO NOT collect any detail information</p>
<p>such as your note content. You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</p>
<p>These data are only used for Boostnote improvements.</p>
<input onChange={(e) => this.handleConfigChange(e)}
checked={this.state.config.amaEnabled}
ref='amaEnabled'
type='checkbox'
/>
Enable to send analytics to our servers<br />
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>Save</button>
</div>
)
}

View File

@@ -41,7 +41,14 @@
a
color #4E8EC6
text-decoration none
.policy
font-size 20px
margin-bottom 10px
.policy-submit
margin-top 10px
body[data-theme="dark"]
.root
color alpha($tab--dark-text-color, 80%)
color alpha($tab--dark-text-color, 80%)

View File

@@ -298,8 +298,8 @@ class StorageItem extends React.Component {
let index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Unlink Storage',
detail: 'This work just detatches a storage from Boostnote. (Any data won\'t be deleted.)',
buttons: ['Confirm', 'Cancel']
detail: 'Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.',
buttons: ['Unlink', 'Cancel']
})
if (index === 0) {

View File

@@ -192,7 +192,7 @@ class UiTab extends React.Component {
<div styleName='group-section'>
<div styleName='group-section-label'>
Switching Preview
Switch to Preview
</div>
<div styleName='group-section-control'>
<select value={config.editor.switchPreview}
@@ -200,7 +200,7 @@ class UiTab extends React.Component {
onChange={(e) => this.handleUIChange(e)}
>
<option value='BLUR'>When Editor Blurred</option>
<option value='RIGHTCLICK'>When Right Clicking</option>
<option value='RIGHTCLICK'>On Right Click</option>
</select>
</div>
</div>
@@ -218,7 +218,7 @@ class UiTab extends React.Component {
<option value='vim'>vim</option>
<option value='emacs'>emacs</option>
</select>
<span styleName='note-for-keymap'>Please reload boostnote after you change the keymap</span>
<span styleName='note-for-keymap'>Please restart boostnote after you change the keymap</span>
</div>
</div>
@@ -271,7 +271,7 @@ class UiTab extends React.Component {
ref='previewLineNumber'
type='checkbox'
/>&nbsp;
Code block line numbering
Show line numbers for preview code blocks
</label>
</div>

View File

@@ -44,7 +44,12 @@ class Preferences extends React.Component {
switch (this.state.currentTab) {
case 'INFO':
return <InfoTab />
return (
<InfoTab
dispatch={dispatch}
config={config}
/>
)
case 'HOTKEY':
return (
<HotkeyTab
@@ -116,7 +121,7 @@ class Preferences extends React.Component {
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='top-bar'>
<p>Your menu for Boostnote</p>
<p>Your preferences for Boostnote</p>
</div>
<ModalEscButton handleEscButtonClick={(e) => this.handleEscButtonClick(e)} />
<div styleName='nav'>

View File

@@ -11,7 +11,8 @@ function defaultDataMap () {
starredSet: new Set(),
storageNoteMap: new Map(),
folderNoteMap: new Map(),
tagNoteMap: new Map()
tagNoteMap: new Map(),
trashedSet: new Set()
}
}
@@ -34,6 +35,10 @@ function data (state = defaultDataMap(), action) {
state.starredSet.add(uniqueKey)
}
if (note.isTrashed) {
state.trashedSet.add(uniqueKey)
}
let storageNoteList = state.storageNoteMap.get(note.storage)
if (storageNoteList == null) {
storageNoteList = new Set(storageNoteList)
@@ -78,6 +83,15 @@ function data (state = defaultDataMap(), action) {
}
}
if (oldNote == null || oldNote.isTrashed !== note.isTrashed) {
state.trashedSet = new Set(state.trashedSet)
if (note.isTrashed) {
state.trashedSet.add(uniqueKey)
} else {
state.trashedSet.delete(uniqueKey)
}
}
// Update storageNoteMap if oldNote doesn't exist
if (oldNote == null) {
state.storageNoteMap = new Map(state.storageNoteMap)
@@ -163,6 +177,11 @@ function data (state = defaultDataMap(), action) {
state.starredSet.delete(originKey)
}
if (originNote.isTrashed) {
state.trashedSet = new Set(state.trashedSet)
state.trashedSet.delete(originKey)
}
// From storageNoteMap
state.storageNoteMap = new Map(state.storageNoteMap)
let noteSet = state.storageNoteMap.get(originNote.storage)
@@ -199,6 +218,15 @@ function data (state = defaultDataMap(), action) {
}
}
if (oldNote == null || oldNote.isTrashed !== note.isTrashed) {
state.trashedSet = new Set(state.trashedSet)
if (note.isTrashed) {
state.trashedSet.add(uniqueKey)
} else {
state.trashedSet.delete(uniqueKey)
}
}
// Update storageNoteMap if oldNote doesn't exist
if (oldNote == null) {
state.storageNoteMap = new Map(state.storageNoteMap)
@@ -283,6 +311,11 @@ function data (state = defaultDataMap(), action) {
state.starredSet.delete(uniqueKey)
}
if (targetNote.isTrashed) {
state.trashedSet = new Set(state.trashedSet)
state.trashedSet.delete(uniqueKey)
}
// From folderNoteMap
let folderKey = targetNote.storage + '-' + targetNote.folder
state.folderNoteMap = new Map(state.folderNoteMap)
@@ -348,6 +381,11 @@ function data (state = defaultDataMap(), action) {
state.starredSet.delete(noteKey)
}
if (note.isTrashed) {
state.trashedSet = new Set(state.trashedSet)
state.trashedSet.delete(noteKey)
}
// Delete key from tag map
state.tagNoteMap = new Map(state.tagNoteMap)
note.tags.forEach((tag) => {

View File

@@ -160,8 +160,7 @@ topBarButtonLight()
height 34px
border-radius 17px
font-size 14px
margin 13px 7px
padding-top 7px
margin 15px 7px
border none
color $ui-button-color
fill $ui-button-color
@@ -169,7 +168,7 @@ topBarButtonLight()
&:active
border-color $ui-button--active-backgroundColor
&:hover
background-color $ui-button--hover-backgroundColor
background-color alpha($ui-button--hover-backgroundColor, 60%)
.control-lockButton-tooltip
opacity 1
@@ -182,7 +181,7 @@ $ui-dark-noteDetail-backgroundColor = #2D3033
$ui-dark-tag-backgroundColor = #3A404C
$dark-background-color = lighten($ui-dark-backgroundColor, 10%)
$ui-dark-text-color = #DDDDDD
$ui-dark-button--active-color = white
$ui-dark-button--active-color = #f4f4f4
$ui-dark-button--active-backgroundColor = #3A404C
$ui-dark-button--hover-backgroundColor = lighten($ui-dark-backgroundColor, 10%)
$ui-dark-button--focus-borderColor = lighten(#369DCD, 25%)
@@ -232,10 +231,12 @@ topBarButtonDark()
color $ui-dark-topbar-button-color
&:hover
background-color $dark-default-button-background--hover
color $ui-dark-tooltip-text-color
&:active
border-color $ui-dark-button--focus-borderColor
&:active:hover
background-color $ui-dark-button--active-backgroundColor
color $ui-dark-tooltip-text-color
&:focus
border-color $ui-button--focus-borderColor

View File

@@ -1,15 +0,0 @@
# Testing for Boostnote
## e2eテスト
Boostnoteには[ava](https://github.com/avajs/ava)と[spectron](https://github.com/electron/spectron)で書かれたe2eテストがあります。
### 実行方法
以下のe2eテストのコマンドがあります。
```
$ yarn run test:e2e
```
もう一つのテストコマンドと分けた理由は、travisCIの都合です。
### travisCIでは
travisCIではmasterブランチで飲みe2eテストを実行するようにしています。もし興味がある方は `.travis.yml`をご覧ください。

View File

@@ -1,20 +0,0 @@
# Тестирование для Boostnote
## Тестирование e2e
Существуют тесты e2e для Boostnote, написанные на [ava](https://github.com/avajs/ava) и [spectron](https://github.com/electron/spectron).
### Как запустить
Для тестирование e2e существует команда:
```
$ yarn run test:e2e
```
Причина, по которой я использую другую команду тестирования - это удобство travisCI.
### TravisCI
Я установил тесты e2e, запущенные на travisCI, только в ветке master. Если вас это интересует, ознакомьтесь с файлом .travis.yml
---
Special thanks:
Translated by @AlexanderBelkevich

View File

@@ -1,15 +0,0 @@
# Testing for Boostnote
## e2e testing
There is e2e tests for Boostnote written in [ava](https://github.com/avajs/ava) and [spectron](https://github.com/electron/spectron).
### How to run
There is a command for e2e testing bellow:
```
$ yarn run test:e2e
```
The reason why I seperate aother test command is because of convenience of travisCI.
### On travisCI
I set e2e tests running on travisCI only master branch. If you're interested in it, please take a look at .travis.yml

View File

@@ -106,6 +106,17 @@ const file = {
{
type: 'separator'
},
{
label: 'Print',
accelerator: 'CommandOrControl+P',
click () {
mainWindow.webContents.send('list:isMarkdownNote')
mainWindow.webContents.send('print')
}
},
{
type: 'separator'
},
{
label: 'Delete Note',
accelerator: macOS ? 'Control+Backspace' : 'Control+Delete',
@@ -192,18 +203,11 @@ const view = {
},
{
label: 'Previous Note',
accelerator: 'Control+U',
accelerator: 'Control+K',
click () {
mainWindow.webContents.send('list:prior')
}
},
{
label: 'Jump to Top',
accelerator: 'Control+G',
click () {
mainWindow.webContents.send('list:jumpToTop')
}
},
{
type: 'separator'
},

View File

@@ -7,6 +7,7 @@
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
<link rel="shortcut icon" href="../resources/favicon.ico">
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css">
<title>Boostnote</title>
<style>
@@ -19,6 +20,15 @@
font-weight: normal;
text-rendering: optimizeLegibility;
}
@font-face {
font-family: 'Lato';
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.ttf') format('truetype');
font-style: normal;
font-weight: normal;
text-rendering: optimizeLegibility;
}
#loadingCover{
background-color: #f4f4f4;
position: absolute;
@@ -64,6 +74,13 @@
<script src="../node_modules/codemirror/addon/edit/continuelist.js"></script>
<script src="../node_modules/codemirror/addon/search/search.js"></script>
<script src="../node_modules/codemirror/addon/search/searchcursor.js"></script>
<script src="../node_modules/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="../node_modules/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="../node_modules/codemirror/addon/search/jump-to-line.js"></script>
<script src="../node_modules/codemirror/addon/dialog/dialog.js"></script>
<script src="../node_modules/raphael/raphael.min.js"></script>
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>
<script>
@@ -87,5 +104,10 @@
scriptEl.setAttribute('src', scriptUrl)
document.body.appendChild(scriptEl)
</script>
<style>
.ace_search {
background-color: #d9d9d9;
}
</style>
</body>
</html>

View File

@@ -1,6 +1,6 @@
{
"name": "boost",
"version": "0.8.11",
"version": "0.8.13",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -10,7 +10,6 @@
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
"compile": "grunt compile",
"test": "PWD=$(pwd) NODE_ENV=test ava",
"test:e2e": "NODE_ENV=test ava tests/e2e/*",
"fix": "npm run lint --fix",
"lint": "eslint .",
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
@@ -113,7 +112,6 @@
"react-input-autosize": "^1.1.0",
"react-router": "^2.4.0",
"react-router-redux": "^4.0.4",
"spectron": "^3.6.2",
"standard": "^8.4.0",
"style-loader": "^0.12.4",
"stylus": "^0.52.4",

View File

@@ -1,40 +0,0 @@
<h1 align="center">
<a href="https://github.com/BoostIO/Boostnote"><img src="./resources/app.png" alt="Boostnote" width="180"></a>
<br>
Boostnote
<br>
<br>
</h1>
<h4 align="center">クールなプログラマーの為の、オープンソースのノートアプリ </h4>
<h5 align="center">macOS, Windows, Linuxで利用できます。</h5>
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
![Boostnote app screenshot](./resources/repository/top.png)
[![Build Status](https://travis-ci.org/BoostIO/Boostnote.svg?branch=master)](https://travis-ci.org/BoostIO/Boostnote)
## Author & Maintainer
- [Rokt33r](https://github.com/rokt33r)
- [sota1235](https://github.com/sota1235)
- [Kohei TAKATA](https://github.com/kohei-takata)
- [asmsuechan](https://github.com/asmsuechan)
- [Kazu Yokomizo](https://github.com/kazup01)
## Contributors
[Great contributors](https://github.com/BoostIO/Boostnote/graphs/contributors) :tada:
## slack group
私たちにはslack groupもあります世界中のプログラマー達と、Boostnoteについてディスカッションをしましょう <br>
[こちらから](https://join.slack.com/boostnote-group/shared_invite/MjAwNTAwNzc4MDM0LTE0OTc5NjIzMDItZjcyOWIyOWY5YQ)
## More Information
* Website: http://boostnote.io/
* Roadmap(upcoming features and bug fixes): https://github.com/BoostIO/Boostnote/wiki/List-of-the-requested-features
* Boostnote Shop(Products are shipped to all over the world :+1:): https://boostnote.paintory.com/
* Donation: [Bountysource](https://salt.bountysource.com/teams/boostnote)
* Development: https://github.com/BoostIO/Boostnote/blob/master/docs/build.md
* Copyright (C) 2017 Maisin&Co.
## License
[GPL v3](./LICENSE).

View File

@@ -6,7 +6,7 @@
<br>
</h1>
<h4 align="center">Note-taking app for programmers. </h4>
<h5 align="center">macOS, Windows and Linux</h5>
<h5 align="center">macOS, Windows and Linux. Android and iOS apps will be released soon!</h5>
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
![Boostnote app screenshot](./resources/repository/top.png)
@@ -25,13 +25,12 @@
## Slack Group
Let's talk about Boostnote's great features, new feature requests and things like Japanese gourmet. 🍣 <br>
[Join us](https://join.slack.com/boostnote-group/shared_invite/MjAwNTAwNzc4MDM0LTE0OTc5NjIzMDItZjcyOWIyOWY5YQ)
[Join us](https://join.slack.com/t/boostnote-group/shared_invite/MjE3NDcwODQ3NTkwLTE1MDA4NjQ3ODktM2IxOTk4ZTNjYQ)
## More Information
* [Website](https://boostnote.io)
* [Boostnote Shop](https://boostnote.paintory.com/) : Products are shipped to all over the world 🌏
* [Donate via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
* [GitHub Issues](https://github.com/BoostIO/Boostnote/issues) : We'd love to hear your feedback 🙌
* [Boostnote Team](https://boostnote.io/team/) : Boostnote for the creative hacker teams. Share your markdown notes and snippets instantly with your team. **We will release it at August!** 🏃💨
* [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md) : Development configurations for Boostnote 🚀
* Copyright (C) 2017 Maisin&Co.

View File

@@ -1,9 +0,0 @@
if [[ ${TRAVIS_OS_NAME} = "linux" ]]; then
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start;
sleep 3
fi
npm install grunt-cli -g
grunt pre-build
npm run test:e2e

View File

@@ -2,11 +2,11 @@
* @fileoverview Unit test for browser/lib/date-formatter.js
*/
const test = require('ava')
const { getLastUpdated } = require('browser/lib/date-formatter')
const { formatDate } = require('browser/lib/date-formatter')
test(t => {
t.throws(
() => getLastUpdated('invalid argument'),
() => formatDate('invalid argument'),
'Invalid argument.'
)
})

View File

@@ -1,39 +0,0 @@
import test from 'ava'
import {Application} from 'spectron'
import path from 'path'
test.beforeEach(async t => {
const boostnotePath = ((platform) => {
switch (platform) {
case 'darwin':
return path.join('..', '..', 'dist', 'Boostnote-darwin-x64', 'Boostnote.app', 'Contents', 'MacOS', 'Boostnote')
case 'linux':
return path.join('..', '..', 'dist', 'Boostnote-linux-x64', 'Boostnote')
}
})(process.platform)
t.context.app = new Application({
path: boostnotePath
})
await t.context.app.start()
})
test.afterEach.always(async t => {
await t.context.app.stop()
})
test(async t => {
const app = t.context.app
await app.client.waitUntilWindowLoaded()
const win = app.browserWindow
t.is(await app.client.getWindowCount(), 1)
t.false(await win.isMinimized())
t.false(await win.isDevToolsOpened())
t.true(await win.isVisible())
t.true(await win.isFocused())
const {width, height} = await win.getBounds()
t.true(width > 0)
t.true(height > 0)
})

View File

@@ -0,0 +1,33 @@
{
"amaEnabled": true,
"editor": {
"fontFamily": "Monaco, Consolas",
"fontSize": "14",
"indentSize": "2",
"indentType": "space",
"keyMap": "vim",
"switchPreview": "BLUR",
"theme": "monokai"
},
"hotkey": {
"toggleFinder": "Cmd + Alt + S",
"toggleMain": "Cmd + Alt + L"
},
"isSideNavFolded": false,
"listStyle": "DEFAULT",
"listWidth": 174,
"navWidth": 200,
"preview": {
"codeBlockTheme": "dracula",
"fontFamily": "Lato",
"fontSize": "14",
"lineNumber": true
},
"sortBy": "UPDATED_AT",
"ui": {
"defaultNote": "ALWAYS_ASK",
"disableDirectWrite": false,
"theme": "default"
},
"zoom": 1
}

View File

@@ -0,0 +1,12 @@
{
"editor": {
"keyMap": "vim",
"switchPreview": "BLUR",
"theme": "monokai",
},
"hotkey": {
"toggleMain": "Control + L"
},
"listWidth": 135,
"navWidth": 135
}

View File

@@ -0,0 +1,12 @@
{
"editor": {
"keyMap": "vim",
"switchPreview": "BLUR",
"theme": "monokai"
},
"hotkey": {
"toggleMain": "Control + L"
},
"listWidth": 135,
"navWidth": 135
}

View File

@@ -0,0 +1,32 @@
const test = require('ava')
const { findStorage } = require('browser/lib/findStorage')
global.document = require('jsdom').jsdom('<body></body>')
global.window = document.defaultView
global.navigator = window.navigator
const Storage = require('dom-storage')
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
const path = require('path')
const TestDummy = require('../fixtures/TestDummy')
const sander = require('sander')
const os = require('os')
const storagePath = path.join(os.tmpdir(), 'test/find-storage')
test.beforeEach((t) => {
t.context.storage = TestDummy.dummyStorage(storagePath)
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
})
// Unit test
test('findStorage() should return a correct storage path(string)', t => {
const storageKey = t.context.storage.cache.key
t.is(findStorage(storageKey).key, storageKey)
t.is(findStorage(storageKey).path, storagePath)
})
test.after(function after () {
localStorage.clear()
sander.rimrafSync(storagePath)
})

View File

@@ -0,0 +1,23 @@
const test = require('ava')
const { getTodoStatus } = require('browser/lib/getTodoStatus')
// Unit test
test('getTodoStatus should return a correct hash object', t => {
// [input, expected]
const testCases = [
['', { total: 0, completed: 0 }],
['* [ ] a\n', { total: 1, completed: 0 }],
['* [ ] a\n* [x] a\n', { total: 2, completed: 1 }],
['- [ ] a\n', { total: 1, completed: 0 }],
['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }]
]
testCases.forEach(testCase => {
const [input, expected] = testCase
t.is(getTodoStatus(input).total, expected.total, `Test for getTodoStatus() input: ${input} expected: ${expected.total}`)
t.is(getTodoStatus(input).completed, expected.completed, `Test for getTodoStatus() input: ${input} expected: ${expected.completed}`)
})
})

View File

@@ -0,0 +1,33 @@
const test = require('ava')
const path = require('path')
const { parse } = require('browser/lib/RcParser')
// Unit test
test('RcParser should return a json object', t => {
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleFinder': 'Cmd + Alt + S', 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
// [input, expected]
const validTestCases = [
['.boostnoterc.valid', validJson],
['.boostnoterc.all', allJson]
]
const invalidTestCases = [
['.boostnoterc.invalid', {}]
]
validTestCases.forEach(validTestCase => {
const [input, expected] = validTestCase
t.is(parse(filePath(input)).editor.keyMap, expected.editor.keyMap, `Test for getTodoStatus() input: ${input} expected: ${expected.keyMap}`)
})
invalidTestCases.forEach(invalidTestCase => {
const [input, expected] = invalidTestCase
t.is(parse(filePath(input)).editor, expected.editor, `Test for getTodoStatus() input: ${input} expected: ${expected.editor}`)
})
})
function filePath (filename) {
return path.join('boostnoterc', filename)
}

View File

@@ -5,7 +5,7 @@ import _ from 'lodash'
const pickContents = (notes) => notes.map((note) => { return note.content })
let noteList = { noteMap: [] }
let notes = []
let note1, note2
test.before(t => {
@@ -14,7 +14,7 @@ test.before(t => {
note1 = dummyNote(data1)
note2 = dummyNote(data2)
noteList.noteMap = [note1, note2]
notes = [note1, note2]
})
test('it can find notes by tags or words', t => {
@@ -30,7 +30,7 @@ test('it can find notes by tags or words', t => {
testCases.forEach((testCase) => {
const [input, expectedContents] = testCase
const results = searchFromNotes(noteList, input)
const results = searchFromNotes(notes, input)
t.true(_.isEqual(pickContents(results).sort(), expectedContents.sort()))
})
})

408
yarn.lock
View File

@@ -1,5 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@rokt33r/markdown-it-math@^4.0.1":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@rokt33r/markdown-it-math/-/markdown-it-math-4.0.2.tgz#87c7172f459833b05e406cfc846e0c0b7ebc24ef"
@@ -123,31 +125,6 @@ aproba@^1.0.3:
version "1.1.1"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
archiver-utils@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174"
dependencies:
glob "^7.0.0"
graceful-fs "^4.1.0"
lazystream "^1.0.0"
lodash "^4.8.0"
normalize-path "^2.0.0"
readable-stream "^2.0.0"
archiver@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/archiver/-/archiver-1.3.0.tgz#4f2194d6d8f99df3f531e6881f14f15d55faaf22"
dependencies:
archiver-utils "^1.3.0"
async "^2.0.0"
buffer-crc32 "^0.2.1"
glob "^7.0.0"
lodash "^4.8.0"
readable-stream "^2.0.0"
tar-stream "^1.5.0"
walkdir "^0.0.11"
zip-stream "^1.1.0"
are-we-there-yet@~1.1.2:
version "1.1.4"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
@@ -294,12 +271,6 @@ async@^1.3.0, async@^1.4.0, async@^1.4.2, async@^1.5.1, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
async@^2.0.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
dependencies:
lodash "^4.14.0"
async@~0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/async/-/async-0.1.22.tgz#0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061"
@@ -312,10 +283,6 @@ asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
atob@~1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773"
autoprefixer@^6.3.1:
version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@@ -1085,7 +1052,7 @@ babel-register@^6.11.6, babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19, babel-runtime@~6.23.0:
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
dependencies:
@@ -1166,12 +1133,6 @@ binary@^0.3.0:
buffers "~0.1.1"
chainsaw "~0.1.0"
bl@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e"
dependencies:
readable-stream "^2.0.5"
bl@~0.9.0:
version "0.9.5"
resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054"
@@ -1250,10 +1211,6 @@ buf-compare@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buf-compare/-/buf-compare-1.0.1.tgz#fef28da8b8113a0a0db4430b0b6467b69730b34a"
buffer-crc32@^0.2.1:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
buffer-equals@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5"
@@ -1453,12 +1410,6 @@ cli-cursor@^1.0.1, cli-cursor@^1.0.2:
dependencies:
restore-cursor "^1.0.1"
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
dependencies:
restore-cursor "^2.0.0"
cli-spinners@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c"
@@ -1604,15 +1555,6 @@ component-emitter@~1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
compress-commons@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.0.tgz#58587092ef20d37cb58baf000112c9278ff73b9f"
dependencies:
buffer-crc32 "^0.2.1"
crc32-stream "^2.0.0"
normalize-path "^2.0.0"
readable-stream "^2.0.0"
compressible@~2.0.8:
version "2.0.10"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd"
@@ -1724,6 +1666,12 @@ cookiejar@2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.6.tgz#0abf356ad00d1c5a219d88d44518046dd026acfe"
copy-to-clipboard@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.6.tgz#13c09bfea0408a5dc5bb987fee3b3986518c9d69"
dependencies:
toggle-selection "^1.0.3"
core-assert@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/core-assert/-/core-assert-0.2.1.tgz#f85e2cf9bfed28f773cc8b3fa5c5b69bdc02fe3f"
@@ -1743,17 +1691,6 @@ core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
crc32-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4"
dependencies:
crc "^3.4.4"
readable-stream "^2.0.0"
crc@^3.4.4:
version "3.4.4"
resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b"
create-error-class@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
@@ -1825,12 +1762,6 @@ css-parse@1.7.x:
version "1.7.0"
resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b"
css-parse@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4"
dependencies:
css "^2.0.0"
css-selector-tokenizer@^0.5.0, css-selector-tokenizer@^0.5.1:
version "0.5.4"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.5.4.tgz#139bafd34a35fd0c1428487049e0699e6f6a2c21"
@@ -1838,19 +1769,6 @@ css-selector-tokenizer@^0.5.0, css-selector-tokenizer@^0.5.1:
cssesc "^0.1.0"
fastparse "^1.1.1"
css-value@~0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea"
css@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc"
dependencies:
inherits "^2.0.1"
source-map "^0.1.38"
source-map-resolve "^0.3.0"
urix "^0.1.0"
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@@ -2017,10 +1935,6 @@ deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
deepmerge@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.3.2.tgz#1663691629d4dbfe364fa12a2a4f0aa86aa3a050"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
@@ -2074,10 +1988,6 @@ detect-indent@^4.0.0:
dependencies:
repeating "^2.0.0"
dev-null@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818"
devtron@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/devtron/-/devtron-1.4.0.tgz#b5e748bd6e95bbe70bfcc68aae6fe696119441e1"
@@ -2142,17 +2052,6 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
ejs@~2.5.6:
version "2.5.6"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88"
electron-chromedriver@~1.7.0:
version "1.7.1"
resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-1.7.1.tgz#008c97976007aa4eb18491ee095e94d17ee47610"
dependencies:
electron-download "^4.1.0"
extract-zip "^1.6.5"
electron-config@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/electron-config/-/electron-config-0.2.1.tgz#7e12c26412d06bf3ed3896d0479df162986b95ba"
@@ -2186,20 +2085,6 @@ electron-download@^3.0.1:
semver "^5.3.0"
sumchecker "^1.2.0"
electron-download@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
dependencies:
debug "^2.2.0"
env-paths "^1.0.0"
fs-extra "^2.0.0"
minimist "^1.2.0"
nugget "^2.0.0"
path-exists "^3.0.0"
rc "^1.1.2"
semver "^5.3.0"
sumchecker "^2.0.1"
electron-gh-releases@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/electron-gh-releases/-/electron-gh-releases-2.0.4.tgz#198c07a0970fb8e80fcc67bd0b4198a010923dc3"
@@ -2283,12 +2168,6 @@ encoding@^0.1.11:
dependencies:
iconv-lite "~0.4.13"
end-of-stream@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
dependencies:
once "^1.4.0"
enhanced-resolve@~0.9.0:
version "0.9.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
@@ -2305,10 +2184,6 @@ env-paths@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-0.3.1.tgz#c30ccfcbc30c890943dc08a85582517ef00da463"
env-paths@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0"
errno@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
@@ -2682,21 +2557,13 @@ extend@3.0.0, extend@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
external-editor@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972"
dependencies:
iconv-lite "^0.4.17"
jschardet "^1.4.2"
tmp "^0.0.31"
extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
dependencies:
is-extglob "^1.0.0"
extract-zip@^1.0.3, extract-zip@^1.6.5:
extract-zip@^1.0.3:
version "1.6.5"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.5.tgz#99a06735b6ea20ea9b705d779acffcc87cff0440"
dependencies:
@@ -2758,12 +2625,6 @@ figures@^1.3.5, figures@^1.4.0:
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
figures@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
dependencies:
escape-string-regexp "^1.0.5"
file-entry-cache@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
@@ -2938,13 +2799,6 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
fs-extra@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^2.1.0"
fs-plus@2.x:
version "2.10.1"
resolved "https://registry.yarnpkg.com/fs-plus/-/fs-plus-2.10.1.tgz#3204781d7840611e6364e7b6fb058c96327c5aa5"
@@ -2999,12 +2853,6 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
gaze@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
dependencies:
globule "^1.0.0"
generate-function@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
@@ -3099,7 +2947,7 @@ glob@^6.0.1, glob@^6.0.3, glob@^6.0.4:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1:
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@@ -3140,14 +2988,6 @@ globby@^5.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
globule@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
dependencies:
glob "~7.1.1"
lodash "~4.16.4"
minimatch "~3.0.2"
got@^5.0.0, got@^5.1.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
@@ -3174,7 +3014,7 @@ graceful-fs@^3.0.0, graceful-fs@^3.0.5:
dependencies:
natives "^1.1.0"
graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@@ -3435,14 +3275,10 @@ humanize-plus@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
iconv-lite@0.4.13:
iconv-lite@0.4.13, iconv-lite@~0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
iconv-lite@^0.4.17, iconv-lite@~0.4.13:
version "0.4.17"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d"
iconv-lite@~0.2.11:
version "0.2.11"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
@@ -3522,24 +3358,6 @@ inquirer@^0.12.0:
strip-ansi "^3.0.0"
through "^2.3.6"
inquirer@~3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347"
dependencies:
ansi-escapes "^1.1.0"
chalk "^1.0.0"
cli-cursor "^2.1.0"
cli-width "^2.0.0"
external-editor "^2.0.1"
figures "^2.0.0"
lodash "^4.3.0"
mute-stream "0.0.7"
run-async "^2.2.0"
rx "^4.1.0"
string-width "^2.0.0"
strip-ansi "^3.0.0"
through "^2.3.6"
interpret@^0.6.4:
version "0.6.6"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
@@ -3844,10 +3662,6 @@ jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
jschardet@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.4.2.tgz#2aa107f142af4121d145659d44f50830961e699a"
jsdom@^9.4.2:
version "9.12.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
@@ -3971,12 +3785,6 @@ lazy-req@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
lazystream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
dependencies:
readable-stream "^2.0.5"
lcid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
@@ -4075,7 +3883,7 @@ lodash@^3.5.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1, lodash@^4.8.0:
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -4087,10 +3895,6 @@ lodash@~2.4.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e"
lodash@~4.16.4:
version "4.16.6"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
@@ -4296,10 +4100,6 @@ mime@1.3.4, mime@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
@@ -4313,7 +4113,7 @@ minimatch@0.3:
lru-cache "2"
sigmund "~1.0.0"
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
@@ -4332,7 +4132,7 @@ minimatch@~0.2.11, minimatch@~0.2.12:
lru-cache "2"
sigmund "~1.0.0"
minimist@0.0.8:
minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
@@ -4340,10 +4140,6 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
mixpanel@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/mixpanel/-/mixpanel-0.4.1.tgz#0e92ee336fb89a164f54830f093c9cae8517fb8f"
@@ -4409,10 +4205,6 @@ mute-stream@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
mute-stream@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
mv@^2.0.3:
version "2.1.1"
resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
@@ -4541,7 +4333,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
normalize-path@^2.0.0, normalize-path@^2.0.1:
normalize-path@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
dependencies:
@@ -4566,10 +4358,6 @@ not-so-shallow@^0.1.3:
dependencies:
buffer-equals "^1.0.3"
npm-install-package@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125"
npmlog@^4.0.2:
version "4.1.0"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
@@ -4659,7 +4447,7 @@ on-headers@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
once@^1.3.0, once@^1.3.3, once@^1.4.0:
once@^1.3.0, once@^1.3.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
@@ -4669,12 +4457,6 @@ onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
dependencies:
mimic-fn "^1.0.0"
open@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
@@ -4729,7 +4511,7 @@ os-locale@^1.4.0:
dependencies:
lcid "^1.0.0"
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@@ -5304,7 +5086,7 @@ punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
q@^1.1.2, q@~1.5.0:
q@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
@@ -5710,7 +5492,7 @@ request@2.55.0:
tough-cookie ">=0.12.0"
tunnel-agent "~0.4.0"
request@^2.45.0, request@^2.65.0, request@^2.79.0, request@^2.81.0, request@~2.81.0:
request@^2.45.0, request@^2.79.0, request@^2.81.0:
version "2.81.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
dependencies:
@@ -5766,10 +5548,6 @@ resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
resolve-url@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
resolve@^1.1.6:
version "1.3.3"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
@@ -5783,17 +5561,6 @@ restore-cursor@^1.0.1:
exit-hook "^1.0.0"
onetime "^1.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
dependencies:
onetime "^2.0.0"
signal-exit "^3.0.2"
rgb2hex@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.0.tgz#ccd55f860ae0c5c4ea37504b958e442d8d12325b"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@@ -5826,12 +5593,6 @@ run-async@^0.1.0:
dependencies:
once "^1.3.0"
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
dependencies:
is-promise "^2.1.0"
run-parallel@^1.1.2:
version "1.1.6"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039"
@@ -5848,11 +5609,7 @@ rx@2.3.24:
version "2.3.24"
resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7"
rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
safe-buffer@^5.0.1, safe-buffer@~5.0.1:
safe-buffer@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
@@ -5954,7 +5711,7 @@ sigmund@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
signal-exit@^3.0.0, signal-exit@^3.0.2:
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -6014,26 +5771,13 @@ source-list-map@^0.1.4, source-list-map@~0.1.7:
version "0.1.8"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
source-map-resolve@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761"
dependencies:
atob "~1.1.0"
resolve-url "~0.2.1"
source-map-url "~0.3.0"
urix "~0.1.0"
source-map-support@^0.4.0, source-map-support@^0.4.2:
version "0.4.15"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1"
dependencies:
source-map "^0.5.6"
source-map-url@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
source-map@0.1.x, source-map@^0.1.38:
source-map@0.1.x:
version "0.1.43"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
dependencies:
@@ -6073,26 +5817,10 @@ spdx-license-ids@^1.0.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
spectron@^3.6.2:
version "3.7.1"
resolved "https://registry.yarnpkg.com/spectron/-/spectron-3.7.1.tgz#818f68584732187d757da1d7a352adfc89ba136b"
dependencies:
dev-null "^0.1.1"
electron-chromedriver "~1.7.0"
request "^2.65.0"
split "^1.0.0"
webdriverio "^4.0.4"
speedometer@~0.1.2:
version "0.1.4"
resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d"
split@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/split/-/split-1.0.0.tgz#c4395ce683abcd254bc28fe1dabb6e5c27dcffae"
dependencies:
through "2"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
@@ -6292,12 +6020,6 @@ sumchecker@^1.2.0:
debug "^2.2.0"
es6-promise "^4.0.5"
sumchecker@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e"
dependencies:
debug "^2.2.0"
superagent-promise@^1.0.3:
version "1.1.0"
resolved "https://registry.yarnpkg.com/superagent-promise/-/superagent-promise-1.1.0.tgz#baf22d8bbdd439a9b07dd10f8c08f54fe2503533"
@@ -6326,7 +6048,7 @@ supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.2.3, supports-color@~3.2.3:
supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
@@ -6388,15 +6110,6 @@ tar-pack@^3.4.0:
tar "^2.2.1"
uid-number "^0.0.6"
tar-stream@^1.5.0:
version "1.5.4"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016"
dependencies:
bl "^1.0.0"
end-of-stream "^1.0.0"
readable-stream "^2.0.0"
xtend "^4.0.0"
tar@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
@@ -6438,7 +6151,7 @@ through2@~0.2.3:
readable-stream "~1.1.9"
xtend "~2.1.1"
through@2, through@^2.3.6:
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -6465,12 +6178,6 @@ tinycolor2@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
tmp@^0.0.31:
version "0.0.31"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
dependencies:
os-tmpdir "~1.0.1"
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@@ -6479,6 +6186,10 @@ to-fast-properties@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
toggle-selection@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.5.tgz#726c703de607193a73c32c7df49cd24950fc574f"
touch@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/touch/-/touch-0.0.3.tgz#51aef3d449571d4f287a5d87c9c8b49181a0db1d"
@@ -6664,10 +6375,6 @@ update-notifier@^1.0.0:
semver-diff "^2.0.0"
xdg-basedir "^2.0.0"
urix@^0.1.0, urix@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
url-parse-lax@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
@@ -6695,7 +6402,7 @@ url@0.10.3:
punycode "1.3.2"
querystring "0.2.0"
url@^0.11.0, url@~0.11.0:
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
dependencies:
@@ -6737,10 +6444,6 @@ validate-npm-package-license@^3.0.1:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
validator@~7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-7.0.0.tgz#c74deb8063512fac35547938e6f0b1504a282fd2"
vary@~1.1.0, vary@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"
@@ -6761,10 +6464,6 @@ vm-browserify@0.0.4:
dependencies:
indexof "0.0.1"
walkdir@^0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532"
warning@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901"
@@ -6785,37 +6484,6 @@ watchpack@^0.2.1:
chokidar "^1.0.0"
graceful-fs "^4.1.2"
wdio-dot-reporter@~0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.8.tgz#36195576da0d998210c71948cbb65f5bf11bfc65"
webdriverio@^4.0.4:
version "4.8.0"
resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.8.0.tgz#d52929b749080f89967f6e1614051cbc8172d132"
dependencies:
archiver "~1.3.0"
babel-runtime "~6.23.0"
css-parse "~2.0.0"
css-value "~0.0.1"
deepmerge "~1.3.2"
ejs "~2.5.6"
gaze "~1.1.2"
glob "~7.1.1"
inquirer "~3.0.6"
json-stringify-safe "~5.0.1"
mkdirp "~0.5.1"
npm-install-package "~2.1.0"
optimist "~0.6.1"
q "~1.5.0"
request "~2.81.0"
rgb2hex "~0.1.0"
safe-buffer "~5.0.1"
supports-color "~3.2.3"
url "~0.11.0"
validator "~7.0.0"
wdio-dot-reporter "~0.0.8"
wgxpath "~1.0.0"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
@@ -6888,10 +6556,6 @@ websocket-extensions@>=0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7"
wgxpath@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690"
whatwg-encoding@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
@@ -7083,13 +6747,3 @@ yauzl@2.4.1:
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
dependencies:
fd-slicer "~1.0.1"
zip-stream@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.1.1.tgz#5216b48bbb4d2651f64d5c6e6f09eb4a7399d557"
dependencies:
archiver-utils "^1.3.0"
compress-commons "^1.1.0"
lodash "^4.8.0"
readable-stream "^2.0.0"