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

Compare commits

...

218 Commits

Author SHA1 Message Date
Kohei TAKATA
a594332ffb Merge pull request #1027 from BoostIO/feature-v0-8-16
v0.8.16
2017-10-28 14:15:41 +09:00
Kohei TAKATA
ceb18ebf1c v0.8.16 2017-10-28 12:28:06 +09:00
Kazu Yokomizo
8910c26ee2 Merge pull request #1016 from PaulRosset/clear-message-HotKeyTab
ClearMessage notification HotKeyTab
2017-10-26 13:53:43 +09:00
Kazu Yokomizo
7549a7bbbe Merge pull request #1014 from asmsuechan/improve-lock-tooltip-text
Change the tooltip text of the lock button for easy to understand what its role
2017-10-26 13:49:57 +09:00
Kazu Yokomizo
17fbe6e232 Merge pull request #1020 from BoostIO/change-init-content
Make <kbd> on keyboard introduction
2017-10-26 10:15:39 +09:00
Kazu Yokomizo
ccdac8f604 Make <kbd> on keyboard introduction 2017-10-26 09:23:12 +09:00
Kazu Yokomizo
88a828c9ef Merge pull request #1019 from filoxo/add-keyboard-markdown
Add keyboard markdown
2017-10-26 08:58:45 +09:00
Carlos Filoteo
ae3291b90e Add keyboard styles 2017-10-25 11:07:03 -06:00
Carlos Filoteo
2c6f0452b8 Require markdown-it-kbd 2017-10-25 10:46:21 -06:00
Carlos Filoteo
4651acd6f4 Install markdown-it-kbd 2017-10-25 10:46:03 -06:00
Kazu Yokomizo
bba7babce3 Merge pull request #1017 from BoostIO/change-crowdfunding
Change crowdfunding Bountysource to OpenCollective.
2017-10-26 00:10:48 +09:00
Kazu Yokomizo
73dc6a4a92 Change crowdfunding Bountysource to OpenCollective. 2017-10-25 23:58:36 +09:00
Paul Rosset
992f5a525a Test build travis with change clearMessage feature 2017-10-25 13:21:30 +01:00
SuenagaRyota
b38d5789f3 Merge pull request #1013 from asmsuechan/change-ISSUETEMPLATE
Change ISSUETEMPLATE to add a sentence dealing with if a user tries to open an issue regarding boostnote mobile
2017-10-25 19:56:25 +09:00
asmsuechan
47b5945e17 Change the tooltip text of the lock button for easy to understand what its role 2017-10-25 19:49:16 +09:00
asmsuechan
73544b0f06 Change ISSUETEMPLATE to add a sentence dealing with if a user tries to open an issue regarding boostnote mobile 2017-10-25 19:45:32 +09:00
Kazu Yokomizo
e7d9311e23 Merge pull request #1010 from PaulRosset/save-notification
Adjust notification HotKeyTab
2017-10-25 10:28:58 +09:00
Paul Rosset
c97c65b707 Delete clearMessage due to problem wih test [WIP] 2017-10-24 23:54:14 +01:00
Paul Rosset
1c02b4e62a Delete setTimeout() due to problem wih test 2017-10-24 23:50:29 +01:00
Paul Rosset
d23156d11a Correction build error 2017-10-24 23:40:15 +01:00
Paul Rosset
bd013adb4d correction eslint syntax 2017-10-24 23:09:21 +01:00
Paul Rosset
c0368ce713 correction 2017-10-24 23:01:16 +01:00
Paul Rosset
80283b5f55 Adjust notification HotKeyTab 2017-10-24 22:27:03 +01:00
Kohei TAKATA
4078645958 Merge pull request #1002 from BoostIO/add-ama-event-for-snippet-lang
Add ama event for snippet lang
2017-10-23 22:33:35 +09:00
Sosuke Suzuki
955ade0b8a add space 2017-10-23 21:12:42 +09:00
Sosuke Suzuki
4b158af9f6 send snippet_lang 2017-10-23 16:35:15 +09:00
Sosuke Suzuki
642fae3ac7 some let => const 2017-10-23 13:51:32 +09:00
SuenagaRyota
d249967aee Merge pull request #1004 from ysshah/patch-1
Fix typo in "Markdown"
2017-10-23 10:47:25 +09:00
Yash Shah
7b6b7f05e0 Fix typo in "Markdown" 2017-10-22 11:10:13 -07:00
Sosuke Suzuki
35b9bf5d34 enable recordDynamicEvent func to passed attribute arg 2017-10-21 18:18:02 +09:00
Sosuke Suzuki
59f0cc4f98 send lang_name of snippet 2017-10-21 16:59:33 +09:00
Kazu Yokomizo
a29ca73fb4 Merge pull request #1000 from BoostIO/fix-sideNav-style
start point of absolute to the right.
2017-10-21 16:18:51 +09:00
Sosuke Suzuki
59b658f059 start point of absolute to the right. 2017-10-21 15:49:47 +09:00
Kazu Yokomizo
3397b3108f Merge pull request #999 from BoostIO/fix-sideNav-style
Fix side nav style
2017-10-21 15:04:26 +09:00
Sosuke Suzuki
cae7baa5e1 change from premitive value to variable 2017-10-21 14:45:26 +09:00
Sosuke Suzuki
4af71fd1dd fix Folded-SideNav size 2017-10-21 14:29:29 +09:00
Sosuke Suzuki
4194b61373 text-align of button-lebels in SideNavFilder are center 2017-10-21 14:11:35 +09:00
Sosuke Suzuki
c91fd6783d fix preference button style 2017-10-21 13:56:21 +09:00
SuenagaRyota
89bbed1dfd Merge pull request #978 from aquibm/master
Fix URIs decoded with mdurl
2017-10-21 13:40:36 +09:00
Sosuke Suzuki
2aeb53920c enable tooltip-label of Preference 2017-10-21 13:37:10 +09:00
Sosuke Suzuki
fe51c232b6 fix typo 2017-10-21 13:27:45 +09:00
Sosuke Suzuki
57b054794c fix position of preference button 2017-10-21 13:25:28 +09:00
SuenagaRyota
8318c56046 Merge pull request #998 from asmsuechan/change-issue-template
Change ISSUE_TEMPLATE because it seems unfriendly
2017-10-21 13:10:54 +09:00
Sosuke Suzuki
0d52417ee7 disable switch-buttons, when NavToggle 2017-10-21 13:06:04 +09:00
asmsuechan
6f3b1b8d6f Change ISSUE_TEMPLATE because it seems unfriendly 2017-10-21 13:05:14 +09:00
Kazu Yokomizo
a460d7722e Merge pull request #996 from BoostIO/update-readme
Update readme
2017-10-21 00:19:00 +09:00
Kazu Yokomizo
d770208d4c Update Backers 2017-10-21 00:14:59 +09:00
Kazu Yokomizo
0434109908 Update Bakcers 2017-10-21 00:11:29 +09:00
Kazu Yokomizo
289d3a4e6b Update Readme 2017-10-21 00:07:39 +09:00
Kazu Yokomizo
ffb9be63c7 Merge pull request #920 from BoostIO/add-ama-options
enable to get appVerion and platformName
2017-10-20 23:05:35 +09:00
Kazu Yokomizo
bf2b53cbce Merge pull request #994 from Visovsiouk/master
Adjust tooltip (#963)
2017-10-19 13:53:40 +09:00
visovsiouk
1d9bf65c31 Adjust tooltip (#963) 2017-10-18 20:29:38 +03:00
Kazu Yokomizo
4744b918d3 Merge pull request #988 from ringohub/fix/982-can_not_scroll_tag_list
Fix #982: Tag list cannot be scroll
2017-10-18 16:35:19 +09:00
Kazu Yokomizo
588b1809a9 Merge pull request #992 from mrseanbaines/sean/fix-grammar
Grammar fix
2017-10-18 16:13:24 +09:00
Sean Baines
dc1c19293d Grammar fix
"Quick search and copy the content of note" to "Quick search and copy the content of a note"
2017-10-17 19:49:51 +01:00
Yoshiki Aoki
1f548959e3 Fix #928: Tag list cannot be scroll 2017-10-17 11:47:06 +09:00
asmsuechan
8cae5670fc Change travis_snapcraft 2017-10-16 15:09:28 +09:00
SuenagaRyota
07c0982d4f Merge pull request #986 from asmsuechan/snapcraft
Snapcraft
2017-10-16 14:07:20 +09:00
SuenagaRyota
2f9e4b3198 Merge pull request #950 from clone1612/catchAnalyticsError
Add try/catch logic to recording of analytics events
2017-10-16 14:06:49 +09:00
asmsuechan
89dba149a3 Change to run build script only master branch 2017-10-16 14:03:19 +09:00
asmsuechan
aa71b4c1b8 Change to snap on travisCI 2017-10-16 13:57:39 +09:00
asmsuechan
43110f8f2a Add boostnote.desktop 2017-10-16 13:57:39 +09:00
asmsuechan
e48540713d Edit snapcraft.yaml to snap Boostnote 2017-10-16 13:57:35 +09:00
asmsuechan
cfd13139e0 snapcraft init 2017-10-16 13:55:32 +09:00
SuenagaRyota
ac5cdf384f Merge pull request #984 from asmsuechan/remove-unused-vars
Remove unused vars
2017-10-15 23:39:50 +09:00
asmsuechan
e9d858d902 Remove unused vars 2017-10-15 23:33:22 +09:00
Kazu Yokomizo
1beae4403a Merge pull request #979 from BoostIO/fix-layout
Fix layout
2017-10-15 17:54:59 +09:00
Kazu Yokomizo
dedf36f704 Position of navToggle button at Sidebar 2017-10-15 17:44:02 +09:00
Kazu Yokomizo
1477de3899 Fix tag layout 2017-10-15 17:40:19 +09:00
Kazu Yokomizo
0d947c7dd8 Fix CI error 2017-10-15 17:25:40 +09:00
Kazu Yokomizo
ebfd8f40e3 Pin to top layout 2017-10-15 17:20:55 +09:00
Kazu Yokomizo
3159cc0ded Add crowdfunding page in Preference 2017-10-15 17:10:58 +09:00
Kazu Yokomizo
10dcbfb891 Fix tags and folder list layout 2017-10-15 16:17:06 +09:00
Kazu Yokomizo
19dc16e14a Change sort icon and string 2017-10-15 15:52:16 +09:00
Kazu Yokomizo
95586b3156 Tag list layout 2017-10-15 15:46:30 +09:00
Kazu Yokomizo
0637daf645 Fix topbar height 2017-10-15 15:31:26 +09:00
Kazu Yokomizo
fdcd62617d Fix position of preference button 2017-10-15 15:30:03 +09:00
Kazu Yokomizo
0f3e5ee4ed Tag button at topbar in sidenav 2017-10-15 15:25:31 +09:00
Kazu Yokomizo
7b171ecc67 Fix layout
- [ ] Pin to top
- [ ] Tag area
- [ ] Preference button
- [ ] Position of New post button
- [ ] Icon of sort button at NoteList and change name of "Updated, Created"
- [ ] Set donation button at side bar in Preference
2017-10-15 11:46:37 +09:00
Sota Sugiura
7a4052ede3 Merge pull request #922 from sosukesuzuki/feature-tag-area
Feature tag area
2017-10-14 16:58:28 +09:00
Aquib Master
3f53a1f629 Fix linting issues 2017-10-14 19:28:11 +13:00
Aquib Master
31daec5fe2 Fix URIs decoded with mdurl
This PR mitigates #918 by retroactively replacing link text decoded by mdurl with the original link.
2017-10-14 19:01:04 +13:00
Sosuke Suzuki
0d7155bda6 implement convertPlatformName function 2017-10-14 12:12:35 +09:00
Sosuke Suzuki
35beec3e39 insert necessary space 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
ff4b96b622 implement tagItem active styleName 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
9b60814292 fix bug : isTrashedActive and isStarredActive are inverted 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
3c4fa83161 modify the arg of arrayOf to the correct 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
e8564f6540 modify propTypes "array" -> "arrayOf" 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
a22e97d4bd add a space after "//" in comment 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
046e6af489 remove extra semicolon and fix indent 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
f805e8a688 cut out NavToggle component 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
2fddc32eb7 cut out StorageList component 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
6018cd5d81 get "data" from this.props 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
3533903be3 duplicate conditions as a variable 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
d867292f66 remove unnecesarry "e" variable 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
7691b662d6 remove unnecesarry "return" 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
86270dd856 add the comment fot complicated condition 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
012e2dde4f remove unnecessary "e" variables 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
ad7a3c49f9 modify to use "const" from "let" 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
e8abd43c8a modify to remove unnecessary "return" 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
3192ce9d39 modify to use PropTypes 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
d09de09fef use color variables 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
4689ddeb98 some rename plural form or easy to understand 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
e300b33a4f fix a mistake in function naming 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
0ca87ea407 fix type description parens () -> {} 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
2886da4f63 give the key props to tagList Item 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
bf9ecb02e5 remove extra parens 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
852617726c complete editting file 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
c2aa35104c remove button width style 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
95e237d4a3 fix style tagList 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
59e5c547e9 fix button style to change color when switch active/inactive 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
06bd2b2b79 add title "tags" 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
faede48217 feature tag search 2017-10-14 11:57:03 +09:00
Sosuke Suzuki
ad0ac19d3d handling tagButton click 2017-10-14 11:49:32 +09:00
Sosuke Suzuki
3154110de1 list tags 2017-10-14 11:49:32 +09:00
Sosuke Suzuki
5248c05e61 switching view and change routing 2017-10-14 11:49:32 +09:00
Sosuke Suzuki
8311030bec add the tag to routing 2017-10-14 11:49:32 +09:00
SuenagaRyota
c429fc6b2c Merge pull request #968 from adrichey/master
Fix: "Uncaught TypeError: Cannot read property 'className' of null"
2017-10-13 23:36:48 +09:00
Alan Richey
590aa9ab17 Fixed the "Uncaught TypeError: Cannot read property 'className' of null" bug that appears when creating folders (coding style adjustments) 2017-10-13 09:30:41 -05:00
SuenagaRyota
f9a7c2d457 Merge pull request #853 from PrimaMateria/feature-rearrange-storage
Feature rearrange storage
2017-10-13 20:16:39 +09:00
Kazu Yokomizo
b4506168fb Merge pull request #972 from asmsuechan/replace-pdf-to-print
Replace pdf to print
2017-10-13 18:11:07 +09:00
SuenagaRyota
f203ab3aaf Merge pull request #973 from asmsuechan/refactor-targetIndex
Add getTargetIndex() and replece them
2017-10-13 17:25:30 +09:00
asmsuechan
c197dd0a4b Add getTargetIndex() and replece them 2017-10-13 17:19:38 +09:00
SuenagaRyota
457e596851 Merge pull request #956 from asmsuechan/pinn-to-top
Pin to top
2017-10-13 17:02:59 +09:00
asmsuechan
d274563b2c Change order for pinned notes on /home, /trashed, /searched or /starred 2017-10-13 16:33:55 +09:00
asmsuechan
2003bea3cf Remove unnecessary lines 2017-10-13 16:24:13 +09:00
asmsuechan
f9b3284852 Fix a condition 2017-10-13 14:22:13 +09:00
asmsuechan
9bca133d88 Remove updateFolder because it's no longer used 2017-10-13 14:18:41 +09:00
asmsuechan
03fc453608 Change method names 2017-10-13 14:18:41 +09:00
asmsuechan
3027cc81b3 Add handleNoteDelete 2017-10-13 14:18:41 +09:00
asmsuechan
2415fbf676 Change to use const instead of let 2017-10-13 14:18:41 +09:00
asmsuechan
725c6a7ba9 Resolve conflicts 2017-10-13 14:18:41 +09:00
asmsuechan
c33da0cf8e Fix some pointed by eslint 2017-10-13 14:18:41 +09:00
asmsuechan
d915d19425 Add comment for NoteItem 2017-10-13 14:18:41 +09:00
asmsuechan
f3370242bf Add conditions to hide pin from /home, /starred or /trash 2017-10-13 14:18:41 +09:00
asmsuechan
0e312ba929 Change name Pinn to Pin 2017-10-13 14:18:41 +09:00
asmsuechan
6440395197 Change to use strict equation 2017-10-13 14:18:41 +09:00
asmsuechan
5433abddaf Remove console.log 2017-10-13 14:18:41 +09:00
asmsuechan
0ccb465288 Remove pinnedNotes from Folder 2017-10-13 14:18:41 +09:00
asmsuechan
8fd4deb3eb Add unpin 2017-10-13 14:18:41 +09:00
asmsuechan
fe8045c51d Add pinn to top 2017-10-13 14:18:41 +09:00
SuenagaRyota
b890c59134 Merge pull request #948 from wrhansen/master
Support for solarized dark and light themes
2017-10-13 13:29:10 +09:00
SuenagaRyota
f39caeb967 Merge pull request #954 from asmsuechan/improve-searching
Improve searching
2017-10-13 12:08:25 +09:00
asmsuechan
7ab482184b Improve tag search by changing the logic 2017-10-13 11:40:10 +09:00
asmsuechan
78b12ae686 Add test 2017-10-13 10:58:32 +09:00
asmsuechan
caa5deac4e Change searching by tag 2017-10-13 10:37:43 +09:00
Kazu Yokomizo
af3083825e Merge pull request #970 from Samatar26/fix-handleCloseButtonClick
Use the correct handler for closing the modal.
2017-10-13 09:35:13 +09:00
asmsuechan
5255708ff2 Replace pdf to print 2017-10-13 09:29:41 +09:00
Samatar26
9331f2034b Use the correct handler for closing the modal.
Relates to #967
2017-10-12 18:01:34 +01:00
Kazu Yokomizo
fc6a5c22bf Merge pull request #969 from Samatar26/fix-button-protrusion
Fixed button protrustion when creating a new folder.
2017-10-13 01:44:17 +09:00
Samatar26
51c397d177 Fixed button protrustion when creating a new folder.
Relates to #966
2017-10-12 17:33:18 +01:00
Alan Richey
7c9596308e Fixed the "Uncaught TypeError: Cannot read property 'className' of null" bug that appears when creating folders 2017-10-12 10:56:07 -05:00
asmsuechan
15dc424ade Change keycode handling scope due to global keyboard support 2017-10-12 23:27:48 +09:00
asmsuechan
49243a8010 Add to handle space key on search 2017-10-12 23:27:45 +09:00
asmsuechan
93e188d118 Change to be able to search on starred 2017-10-12 20:28:23 +09:00
asmsuechan
df3195fc1e Refactor getContextNotes() 2017-10-12 18:42:34 +09:00
asmsuechan
da6b8c30a0 Improve some 2017-10-12 18:42:34 +09:00
asmsuechan
70468b6b7d Change contextNotes a state to a variable because of lifesycle loop 2017-10-12 18:42:34 +09:00
asmsuechan
2511512d94 Improve context search 2017-10-12 18:42:34 +09:00
asmsuechan
4418617d3b Delete a unnecessary break 2017-10-12 18:42:34 +09:00
asmsuechan
6e480ba146 Add comments 2017-10-12 18:42:34 +09:00
asmsuechan
b4f5913a80 Fix to work inputting by IME on search 2017-10-12 18:42:34 +09:00
Kazu Yokomizo
6a3062709c Merge pull request #951 from mrseanbaines/sean/grammar-fix
Grammar and capitalization fix
2017-10-12 14:37:34 +09:00
Kazu Yokomizo
d66bc1faef Merge pull request #943 from voidsatisfaction/add_context_menu_delete_note
Add notelist right click(context menu) and delete note
2017-10-12 14:34:51 +09:00
Kazu Yokomizo
bef7d45c3e Merge pull request #961 from asmsuechan/fix-pasting-image
Fix to create imageDir if it does not exist
2017-10-12 11:48:20 +09:00
SuenagaRyota
bb9489a8d3 Merge pull request #955 from asmsuechan/iss-919
Change to apply font with single quotations
2017-10-12 11:34:42 +09:00
asmsuechan
700eeb8f5a Fix to create imageDir if it does not exist 2017-10-12 10:28:01 +09:00
asmsuechan
7e2f0049b6 Change to apply font with single quotations 2017-10-11 12:17:49 +09:00
Sean Baines
b2388544d8 Merge branch 'master' into sean/grammar-fix 2017-10-10 19:22:02 +01:00
Sosuke Suzuki
d772551c60 convert platformName from os.platfoem() form to AMA form 2017-10-10 14:58:52 +09:00
Wesley Hansen
31dca6f06b Fix failed build lint error 2017-10-09 20:55:04 -04:00
Sean Baines
83f68fe153 Grammar and capitalization fix 2017-10-09 19:15:52 +01:00
Kazu Yokomizo
08a2ae0fd3 Merge pull request #941 from voidsatisfaction/korean_trans_dev
Add recent translated korean developement & debug docs
2017-10-10 01:21:56 +09:00
Jannick Hemelhof
53d3f51c74 Cleaner catch 2017-10-09 14:04:02 +02:00
Jannick Hemelhof
f7cdafb087 Add try/catch logic to recording of analytics events 2017-10-09 10:45:09 +02:00
Wesley Hansen
5b17808569 Support for solarized dark and light themes
CodeMirror seems to have the two solarized themes within the
`node_modules/coemirror/theme/solarized.css`. So passing the string
"solarized light" and "solarized dark" to the editor theme appropriately
sets these themes.

The Boostnote app appears to be dynamically determining themes based
on the css files found within `node_modules/codemirror/theme/`.
So that's why there was just a single option of 'solarized' before.

The light and dark 'solarized' themes appear to be the *only* themes
that share a css style, whereas all other light and dark variarnt
themes get their own css file (ex: base16-dark.css and base16-light.css).

Weird!
2017-10-08 23:56:15 -04:00
voidSatisfaction
a7328e21f1 feat: add right click notelist delete 2017-10-08 18:20:31 +09:00
voidSatisfaction
e64370e9a2 fix: no need enter 2017-10-08 15:16:26 +09:00
voidSatisfaction
d5b37b2418 feat: add debug docs for korean and link on debug.md 2017-10-08 13:58:15 +09:00
voidSatisfaction
4da08d93fd feat: add translated korean developement docs 2017-10-08 13:39:32 +09:00
Kazu Yokomizo
c39e5c67f5 Merge pull request #937 from mrseanbaines/sean/improve-english
Sean/improve english
2017-10-06 13:21:35 +09:00
Sean Baines
00d5cf13c9 Merge branch 'master' into sean/improve-english 2017-10-05 07:46:02 +01:00
Kazu Yokomizo
1120bcfc0c Merge pull request #934 from mrseanbaines/sean/tag-select-border-box
Fix "borde-box" typo
2017-10-05 10:49:39 +09:00
Sean Baines
8e506cb7c2 Improve English
This would make more sense like this.
2017-10-04 21:50:15 +01:00
Sean Baines
145b66d375 Fix English mistake 2017-10-04 21:46:55 +01:00
Sean Baines
82e4a8bbc3 Fix borde-box typo
Mistake in code. Changed from `borde-box` to `border-box`
2017-10-04 21:33:49 +01:00
Kazu Yokomizo
bca9bfb960 Merge pull request #931 from BoostIO/fix-font-color-in-code
Fix font color in code block
2017-10-04 13:11:55 +09:00
Kazu Yokomizo
d8e19d9c17 Fix font color in code block 2017-10-04 11:39:27 +09:00
SuenagaRyota
95d74d1ca2 Merge pull request #897 from urda/urda/feature/copy-notify-toggle
Allow users to disable "Saved to clipboard" notification.
2017-10-01 19:33:17 +09:00
Peter Urda
ebdd6d77f7 Allow users to disable "Saved to clipboard" notification. 2017-10-01 02:48:54 -07:00
Sosuke Suzuki
d56bcc4fdf enable to get appVerion and platformName 2017-09-30 12:19:51 +09:00
Kazu Yokomizo
4bb18cfc9a Merge pull request #915 from cofcool/fix_doc
change grand to grunt
2017-09-27 13:01:45 +09:00
CofCool
6f30692534 grand -> grunt 2017-09-27 11:49:05 +08:00
Kazu Yokomizo
e249c1ec65 Merge pull request #911 from sferra/place-notification-to-the-right
Place notifications on the right side of the notification bar
2017-09-26 18:37:49 +09:00
Cristian Beskid
c2b4c77003 Place notifications on the right side 2017-09-26 10:35:58 +02:00
Kazu Yokomizo
e64733827a Merge pull request #906 from sferra/fix-collapse-sidebar-button-not-visible
Align notification bar with the navigation bar
2017-09-26 13:02:24 +09:00
Cristian Beskid
ea81b0d414 Fix notification bar offset in full screen mode 2017-09-25 23:08:12 +02:00
Cristian Beskid
000cf2a864 Center notification in the notification bar 2017-09-25 18:44:22 +02:00
Cristian Beskid
dc13b919b3 Fix incorrect notification bar width 2017-09-25 17:34:40 +02:00
Cristian Beskid
a0c8ec3171 Remove redundant semicolon 2017-09-25 17:26:08 +02:00
Cristian Beskid
80c13f7c4f Align notification bar with the navigation bar 2017-09-25 17:17:34 +02:00
Kazu Yokomizo
1a6f3d808b Merge pull request #899 from BoostIO/change-font-color-at-code-in-default
Change font color in code at default theme
2017-09-24 13:35:21 +09:00
Kazu Yokomizo
ec8fac1199 Change font color in code at default theme 2017-09-24 13:24:14 +09:00
Kazu Yokomizo
98c93d3248 Merge pull request #895 from Overload119/fix_grammar
Fix grammer in InfoTab
2017-09-24 12:00:18 +09:00
Amir Sharif
a053706c24 Fix grammer in InfoTab 2017-09-23 09:10:33 -07:00
Matus Benko
43c49f54d2 used findStorage function in the updateFolder 2017-09-11 21:10:44 +02:00
Matus Benko
a15dfffa44 used findStorage function in the reorderFolder 2017-09-11 21:09:51 +02:00
Matus Benko
59985dee72 fixed test title 2017-09-09 21:53:10 +02:00
Matus Benko
6b7132f134 fixed style of dragged folder item for dark theme 2017-09-09 21:50:06 +02:00
Matus Benko
5c2c99282d added test for reorderFolder 2017-09-08 18:58:35 +02:00
Matus Benko
94e6f89d07 fixed errors from lint 2017-09-08 18:46:17 +02:00
Matus Benko
3804a746df connected sortable folder list to data api 2017-09-08 12:07:59 +02:00
Matus Benko
5c2d7e2d2a fixed typo in the useDragHandle attribute for the folder list 2017-09-08 00:59:38 +02:00
Matus Benko
c34dd462b6 made sortable item helper visible by setting proper zindex 2017-09-08 00:41:20 +02:00
Matus Benko
9141b1a641 saving new order in the storage only for now 2017-09-08 00:09:13 +02:00
Matus Benko
0fea85e2f2 added drag handle to the folder item 2017-09-07 23:52:27 +02:00
Matus Benko
a58c191ded used react-sortable-hoc on folderList and folderItem 2017-09-06 22:56:32 +02:00
Matus Benko
77089a1178 extracted folder list and item to separate components 2017-09-06 20:02:47 +02:00
72 changed files with 1914 additions and 903 deletions

Binary file not shown.

View File

@@ -1,6 +1,20 @@
language: node_js
node_js:
- 'stable'
- 'lts/*'
script: npm run lint && npm run test
- stable
- lts/*
script:
- npm run lint && npm run test
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then npm install -g grunt npm@5.2 && grunt pre-build; fi'
after_success:
- openssl aes-256-cbc -K $encrypted_440d7f9a3c38_key -iv $encrypted_440d7f9a3c38_iv
-in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
sudo: required
services:
- docker
deploy:
'on':
branch: master
provider: script
script: if [ ${TRAVIS_NODE_VERSION} = "stable" ];then docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c "apt update -qq
&& cd $(pwd) && snapcraft && snapcraft push *.snap --release edge"; fi
skip_cleanup: true

View File

@@ -1,9 +1,39 @@
Become a [backer](https://salt.bountysource.com/teams/boostnote) and support Boostnote!
You can support Boostnote from $ 5 a month!
Dear all,
# Backers
[Kazu Yokomizo](https://twitter.com/kazup_bot)
Thanks for your using!
Boostnote is used in about 200 countries and regions, it is a awesome developer community.
kolchan11
To continue supporting this growth, and to satisfy community expectations,
we would like to invest more time in this project.
RonWalker22
If you like this project and see its potential, you can help!
Thanks,
Boostnote maintainers.
### >> [Support via OpenCollective](https://opencollective.com/boostnoteio)
---
## Backers
[Kazz](https://twitter.com/kazup_bot) - $65
Intense Raiden - $45
ravy22 - $25
trentpolack - $20
hikariru - $10
kolchan11 - $10
RonWalker22 - $10
hocchuc - $5
Adam - $5
Steve - $5
evmin - $5

View File

@@ -1 +1,3 @@
Please paste some **screenshots** with the **developer tool** open if you report a bug.
Please paste some **screenshots** with the **developer tool** open (console tab) when you report a bug.
If your issue is regarding boostnote mobile, move to https://github.com/BoostIO/boostnote-mobile.

View File

@@ -4,6 +4,7 @@ import CodeMirror from 'codemirror'
import path from 'path'
import copyImage from 'browser/main/lib/dataApi/copyImage'
import { findStorage } from 'browser/lib/findStorage'
import fs from 'fs'
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
@@ -232,9 +233,10 @@ export default class CodeEditor extends React.Component {
const binaryData = new Buffer(base64data, 'base64').toString('binary')
const imageName = Math.random().toString(36).slice(-16)
const storagePath = findStorage(this.props.storageKey).path
const imagePath = path.join(`${storagePath}`, 'images', `${imageName}.png`)
require('fs').writeFile(imagePath, binaryData, 'binary')
const imageDir = path.join(storagePath, 'images')
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
const imagePath = path.join(imageDir, `${imageName}.png`)
fs.writeFile(imagePath, binaryData, 'binary')
const imageMd = `![${imageName}](${path.join('/:storage', `${imageName}.png`)})`
this.insertImageMd(imageMd)
}

View File

@@ -266,6 +266,7 @@ class MarkdownEditor extends React.Component {
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
/>
</div>

View File

@@ -10,6 +10,7 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
import fs from 'fs'
import htmlTextHelper from 'browser/lib/htmlTextHelper'
import copy from 'copy-to-clipboard'
import mdurl from 'mdurl'
const { remote } = require('electron')
const { app } = remote
@@ -34,13 +35,12 @@ function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber) {
}
${markdownStyle}
body {
font-family: ${fontFamily.join(', ')};
font-family: '${fontFamily.join("','")}';
font-size: ${fontSize}px;
}
code {
font-family: ${codeBlockFontFamily.join(', ')};
background-color: rgba(0,0,0,0.04);
color: #CC305F;
}
.lineNumber {
${lineNumber && 'display: block !important;'}
@@ -184,6 +184,14 @@ export default class MarkdownPreview extends React.Component {
})
}
fixDecodedURI (node) {
const { innerText, href } = node
node.innerText = mdurl.decode(href) === innerText
? href
: innerText
}
componentDidMount () {
this.refs.root.setAttribute('sandbox', 'allow-scripts')
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
@@ -224,6 +232,7 @@ export default class MarkdownPreview extends React.Component {
prevProps.codeBlockFontFamily !== this.props.codeBlockFontFamily ||
prevProps.codeBlockTheme !== this.props.codeBlockTheme ||
prevProps.lineNumber !== this.props.lineNumber ||
prevProps.showCopyNotification !== this.props.showCopyNotification ||
prevProps.theme !== this.props.theme) {
this.applyStyle()
this.rewriteIframe()
@@ -262,7 +271,7 @@ export default class MarkdownPreview extends React.Component {
el.removeEventListener('click', this.linkClickHandler)
})
let { value, theme, indentSize, codeBlockTheme, storagePath } = this.props
let { value, theme, indentSize, codeBlockTheme, showCopyNotification, storagePath } = this.props
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
@@ -279,6 +288,7 @@ export default class MarkdownPreview extends React.Component {
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
this.fixDecodedURI(el)
el.addEventListener('click', this.anchorClickHandler)
})
@@ -309,10 +319,12 @@ export default class MarkdownPreview extends React.Component {
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
copyIcon.onclick = (e) => {
copy(content)
this.notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!',
silent: true
})
if (showCopyNotification) {
this.notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!',
silent: true
})
}
}
el.parentNode.appendChild(copyIcon)
el.innerHTML = ''
@@ -426,5 +438,6 @@ MarkdownPreview.propTypes = {
onMouseDown: PropTypes.func,
className: PropTypes.string,
value: PropTypes.string,
showCopyNotification: PropTypes.bool,
storagePath: PropTypes.string
}

View File

@@ -0,0 +1,29 @@
/**
* @fileoverview Micro component for toggle SideNav
*/
import React, { PropTypes } from 'react'
import styles from './NavToggleButton.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {boolean} isFolded
* @param {Function} handleToggleButtonClick
*/
const NavToggleButton = ({isFolded, handleToggleButtonClick}) => (
<button styleName='navToggle'
onClick={(e) => handleToggleButtonClick(e)}
>
{isFolded
? <i className='fa fa-angle-double-right' />
: <i className='fa fa-angle-double-left' />
}
</button>
)
NavToggleButton.propTypes = {
isFolded: PropTypes.bool.isRequired,
handleToggleButtonClick: PropTypes.func.isRequired
}
export default CSSModules(NavToggleButton, styles)

View File

@@ -0,0 +1,19 @@
.navToggle
navButtonColor()
display block
position absolute
left 5px
bottom 5px
border-radius 16.5px
height 34px
width 34px
line-height 32px
padding 0
body[data-theme="dark"]
.navToggle
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s
color $ui-dark-text-color

View File

@@ -41,16 +41,18 @@ 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, handleDragStart }) => (
const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteContextMenu, handleDragStart, pathname }) => (
<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 +72,9 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleDragStar
{note.isStarred
? <i styleName='item-star' className='fa fa-star' /> : ''
}
{note.isPinned && !pathname.match(/\/home|\/starred|\/trash/)
? <i styleName='item-pin' className='fa fa-thumb-tack' /> : ''
}
{note.type === 'MARKDOWN_NOTE'
? <TodoProcess todoStatus={getTodoStatus(note.content)} />
: ''
@@ -99,6 +104,7 @@ NoteItem.propTypes = {
isTrashed: PropTypes.bool.isRequired
}),
handleNoteClick: PropTypes.func.isRequired,
handleNoteContextMenu: PropTypes.func.isRequired,
handleDragStart: PropTypes.func.isRequired,
handleDragEnd: PropTypes.func.isRequired
}

View File

@@ -126,6 +126,17 @@ $control-height = 30px
padding 0
border-radius 17px
.item-pin
position absolute
right -21px
bottom 28px
width 34px
height 34px
color #E54D42
font-size 14px
padding 0
border-radius 17px
body[data-theme="dark"]
.root
border-color $ui-dark-borderColor

View File

@@ -45,7 +45,7 @@ class RealtimeNotification extends React.Component {
: ''
return (
<div styleName='notification-area'>{link}</div>
<div styleName='notification-area' style={this.props.style}>{link}</div>
)
}
}

View File

@@ -3,21 +3,20 @@
font-size 12px
position absolute
bottom 0px
right 0px
background-color #EBEBEB
width 100vw
height 30px
text-align center
.notification-link
position absolute
right 5px
top 5px
text-decoration none
color #282A36
border 1px solid #6FA8E6
background-color alpha(#6FA8E6, 0.2)
padding 3px 9px
border-radius 2px
position absolute
bottom 4px
margin-left -10%
transition 0.2s
&:hover
color #1378BD
@@ -32,4 +31,4 @@ body[data-theme="dark"]
background-color alpha(#5CB85C, 0.2)
transition 0.2s
&:hover
color #5CB85C
color #5CB85C

View File

@@ -17,12 +17,12 @@
.menu-button-label
color $ui-text-color
&:hover
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 50%)
color #e74c3c
.menu-button-label
color $ui-text-color
@@ -34,12 +34,12 @@
.menu-button-label
color $ui-text-color
&:hover
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
&:active, &:active:hover
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 50%)
color #F9BF3B
.menu-button-label
color $ui-text-color
@@ -88,7 +88,7 @@ body[data-theme="dark"]
.menu-button-label
color $ui-dark-text-color
&:hover
background-color $ui-dark-button--active-backgroundColor
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
color #c0392b
.menu-button-label
color $ui-dark-text-color
@@ -99,7 +99,7 @@ body[data-theme="dark"]
.menu-button-label
color $ui-dark-text-color
&:hover
background-color $ui-dark-button--active-backgroundColor
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
color $ui-favorite-star-button-color
.menu-button-label
color $ui-dark-text-color
color $ui-dark-text-color

View File

@@ -30,7 +30,7 @@
background-color $ui-button--active-backgroundColor
&:hover
color $ui-text-color
background-color $ui-button--active-backgroundColor
background-color alpha($ui-button--active-backgroundColor, 50%)
.folderList-item-name
display block
@@ -86,7 +86,7 @@ body[data-theme="dark"]
color $ui-dark-text-color
background-color $ui-dark-button--active-backgroundColor
&:active
background-color $ui-dark-button--active-backgroundColor
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
&:hover
color $ui-dark-text-color
background-color $ui-dark-button--active-backgroundColor
background-color alpha($ui-dark-button--active-backgroundColor, 50%)

View File

@@ -0,0 +1,23 @@
/**
* @fileoverview Micro component for showing StorageList
*/
import React, { PropTypes } from 'react'
import styles from './StorgaeList.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {Array} storgaeList
*/
const StorageList = ({storageList}) => (
<div styleName='storageList'>
{storageList.length > 0 ? storageList : (
<div styleName='storgaeList-empty'>No storage mount.</div>
)}
</div>
)
StorageList.propTypes = {
storgaeList: PropTypes.arrayOf(PropTypes.element).isRequired
}
export default CSSModules(StorageList, styles)

View File

@@ -0,0 +1,20 @@
.storageList
absolute left right
bottom 37px
top 160px
overflow-y auto
.storageList-empty
padding 0 10px
margin-top 15px
line-height 24px
color $ui-inactive-text-color
body[data-theme="dark"]
.storageList-empty
color $ui-dark-inactive-text-color
.root-folded
.storageList-empty
white-space nowrap
transform rotate(90deg)

View File

@@ -0,0 +1,27 @@
/**
* @fileoverview Micro component for showing TagList.
*/
import React, { PropTypes } from 'react'
import styles from './TagListItem.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {string} name
* @param {Function} handleClickTagListItem
* @param {bool} isActive
*/
const TagListItem = ({name, handleClickTagListItem, isActive}) => (
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
<span styleName='tagList-item-name'>
{`# ${name}`}
</span>
</button>
)
TagListItem.propTypes = {
name: PropTypes.string.isRequired,
handleClickTagListItem: PropTypes.func.isRequired
}
export default CSSModules(TagListItem, styles)

View File

@@ -0,0 +1,67 @@
.tagList-item
display flex
width 100%
height 26px
background-color transparent
color $ui-inactive-text-color
padding 0
margin-bottom 5px
text-align left
border none
overflow ellipsis
font-size 12px
&:first-child
margin-top 0
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
transition background-color 0.15s
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
.tagList-item-active
background-color $ui-button--active-backgroundColor
display flex
width 100%
height 26px
padding 0
margin-bottom 5px
text-align left
border none
overflow ellipsis
font-size 12px
&:hover
background-color alpha($ui-button--active-backgroundColor, 60%)
transition 0.2s
.tagList-item-name
display block
flex 1
padding 0 25px
height 26px
line-height 26px
border-width 0 0 0 2px
border-style solid
border-color transparent
overflow hidden
text-overflow ellipsis
body[data-theme="dark"]
.tagList-item
color $ui-dark-inactive-text-color
&:hover
color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
&:active
color $ui-dark-text-color
background-color $ui-dark-button--active-backgroundColor
.tagList-item-active
background-color $ui-dark-button--active-backgroundColor
color $ui-dark-text-color
&:active
background-color alpha($ui-dark-button--active-backgroundColor, 50%)
&:hover
color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 50%)

View File

@@ -193,6 +193,7 @@ ol
&>li>ul, &>li>ol
margin 0
code
color #CC305F
padding 0.2em 0.4em
background-color #f7f7f7
border-radius 3px
@@ -268,6 +269,16 @@ table
border-color borderColor
&:last-child
border-right solid 1px borderColor
kbd
background-color #fafbfc
border solid 1px borderColor
border-bottom-color btnColor
border-radius 3px
box-shadow inset 0 -1px 0 #959da5
display inline-block
font-size .8em
line-height 1
padding 3px 5px
themeDarkBackground = darken(#21252B, 10%)
themeDarkText = #f9f9f9
@@ -316,3 +327,6 @@ body[data-theme="dark"]
border-color themeDarkTableBorder
&:last-child
border-right solid 1px themeDarkTableBorder
kbd
background-color themeDarkBorder
color themeDarkText

View File

@@ -196,6 +196,7 @@ class NoteDetail extends React.Component {
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
value={note.content}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
/>
)

View File

@@ -10,6 +10,7 @@ const themes = fs.readdirSync(themePath)
.map((themePath) => {
return themePath.substring(0, themePath.lastIndexOf('.'))
})
themes.splice(themes.indexOf('solarized'), 1, 'solarized dark', 'solarized light')
const consts = {
FOLDER_COLORS: [

View File

@@ -68,6 +68,7 @@ md.use(require('markdown-it-named-headers'), {
.replace(/\-+$/, '')
}
})
md.use(require('markdown-it-kbd'))
// Override task item
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token

View File

@@ -2,15 +2,16 @@ import _ from 'lodash'
export default function searchFromNotes (notes, search) {
if (search.trim().length === 0) return []
let searchBlocks = search.split(' ')
const searchBlocks = search.split(' ').filter(block => { return block !== '' })
let foundNotes = findByWord(notes, searchBlocks[0])
searchBlocks.forEach((block) => {
foundNotes = findByWord(foundNotes, block)
if (block.match(/^#.+/)) {
notes = findByTag(notes, block)
} else {
notes = findByWord(notes, block)
foundNotes = foundNotes.concat(findByTag(notes, block))
}
})
return notes
return foundNotes
}
function findByTag (notes, block) {

View File

@@ -3,7 +3,7 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl'
const InfoPanel = ({
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type, print
}) => (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div styleName='group-section'>
@@ -79,9 +79,9 @@ const InfoPanel = ({
<p>.txt</p>
</button>
<button styleName='export--unable'>
<i className='fa fa-file-pdf-o fa-fw' />
<p>.pdf</p>
<button styleName='export--enable' onClick={(e) => print(e)}>
<i className='fa fa-print fa-fw' />
<p>Print</p>
</button>
</div>
</div>
@@ -97,7 +97,8 @@ InfoPanel.propTypes = {
exportAsTxt: PropTypes.func.isRequired,
wordCount: PropTypes.number,
letterCount: PropTypes.number,
type: PropTypes.string.isRequired
type: PropTypes.string.isRequired,
print: PropTypes.func.isRequired
}
export default CSSModules(InfoPanel, styles)

View File

@@ -256,6 +256,10 @@ class MarkdownNoteDetail extends React.Component {
if (infoPanel.style) infoPanel.style.display = infoPanel.style.display === 'none' ? 'inline' : 'none'
}
print (e) {
ee.emit('print')
}
render () {
let { data, config, location } = this.props
let { note } = this.state
@@ -330,7 +334,7 @@ class MarkdownNoteDetail extends React.Component {
>
<i className={faClassName} styleName='lock-button' />
<span styleName='control-lockButton-tooltip'>
{this.state.isLocked ? 'Unlock' : 'Lock'}
{this.state.isLocked ? 'Unlock Editor' : 'Keep Editor Locked'}
</span>
</button>
return (
@@ -357,6 +361,7 @@ class MarkdownNoteDetail extends React.Component {
wordCount={note.content.split(' ').length}
letterCount={note.content.replace(/\r?\n/g, '').length}
type={note.type}
print={this.print}
/>
</div>
</div>

View File

@@ -266,11 +266,16 @@ class SnippetNoteDetail extends React.Component {
}
renameSnippetByIndex (index, name) {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].name = name
let syntax = CodeMirror.findModeByFileName(name.trim())
let mode = syntax != null ? syntax.name : null
if (mode != null) snippets[index].mode = mode
const syntax = CodeMirror.findModeByFileName(name.trim())
const mode = syntax != null ? syntax.name : null
if (mode != null) {
snippets[index].mode = mode
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SNIPPET_LANG', {
name: mode
})
}
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({
@@ -291,6 +296,10 @@ class SnippetNoteDetail extends React.Component {
}, () => {
this.save()
})
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SELECT_LANG', {
name
})
}
}

View File

@@ -51,7 +51,7 @@
margin 2px 0 15px 2px
vertical-align middle
height 18px
box-sizing borde-box
box-sizing border-box
border none
background-color transparent
outline none

View File

@@ -21,6 +21,7 @@ function focused () {
}
class Main extends React.Component {
constructor (props) {
super(props)
@@ -189,6 +190,17 @@ class Main extends React.Component {
render () {
let { config } = this.props
// the width of the navigation bar when it is folded/collapsed
const foldedNavigationWidth = 44
let notificationBarOffsetLeft
if (this.state.fullScreen) {
notificationBarOffsetLeft = 0
} else if (config.isSideNavFolded) {
notificationBarOffsetLeft = foldedNavigationWidth
} else {
notificationBarOffsetLeft = this.state.navWidth
}
return (
<div
className='Main'
@@ -217,7 +229,7 @@ class Main extends React.Component {
<div styleName={config.isSideNavFolded ? 'body--expanded' : 'body'}
id='main-body'
ref='body'
style={{left: config.isSideNavFolded ? 44 : this.state.navWidth}}
style={{left: config.isSideNavFolded ? foldedNavigationWidth : this.state.navWidth}}
>
<TopBar style={{width: this.state.listWidth}}
{..._.pick(this.props, [
@@ -256,7 +268,9 @@ class Main extends React.Component {
ignorePreviewPointerEvents={this.state.isRightSliderFocused}
/>
</div>
<RealtimeNotification />
<RealtimeNotification
style={{left: notificationBarOffsetLeft}}
/>
</div>
)
}

View File

@@ -4,7 +4,6 @@
height $topBar-height - 1
margin-left: auto;
width: 64px;
margin-right: -15px;
.root--expanded
@extend .root
@@ -14,10 +13,8 @@ $control-height = 34px
.control
position absolute
top 13px
left 8px
right 8px
right 7px
height $control-height
overflow hidden
display flex
.control-newNoteButton
@@ -35,10 +32,11 @@ $control-height = 34px
.control-newNoteButton-tooltip
tooltip()
position fixed
position absolute
pointer-events none
top 50px
left 433px
top 26px
right -43px
width 124px
z-index 200
padding 5px
line-height normal

View File

@@ -14,6 +14,7 @@ import { hashHistory } from 'react-router'
import markdown from 'browser/lib/markdown'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import stripgtags from 'striptags'
import store from 'browser/main/store'
const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote
@@ -52,6 +53,8 @@ class NoteList extends React.Component {
this.state = {
}
this.contextNotes = []
}
componentDidMount () {
@@ -90,6 +93,7 @@ class NoteList extends React.Component {
if (this.notes.length > 0 && location.query.key == null) {
let { router } = this.context
if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes()
router.replace({
pathname: location.pathname,
query: {
@@ -101,9 +105,7 @@ class NoteList extends React.Component {
// Auto scroll
if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) {
let targetIndex = _.findIndex(this.notes, (note) => {
return note != null && note.storage + '-' + note.key === location.query.key
})
const targetIndex = this.getTargetIndex()
if (targetIndex > -1) {
let list = this.refs.list
let item = list.childNodes[targetIndex]
@@ -129,9 +131,7 @@ class NoteList extends React.Component {
let { router } = this.context
let { location } = this.props
let targetIndex = _.findIndex(this.notes, (note) => {
return note.storage + '-' + note.key === location.query.key
})
let targetIndex = this.getTargetIndex()
if (targetIndex === 0) {
return
@@ -154,9 +154,7 @@ class NoteList extends React.Component {
let { router } = this.context
let { location } = this.props
let targetIndex = _.findIndex(this.notes, (note) => {
return note.storage + '-' + note.key === location.query.key
})
let targetIndex = this.getTargetIndex()
if (targetIndex === this.notes.length - 1) {
targetIndex = 0
@@ -184,9 +182,7 @@ class NoteList extends React.Component {
const { router } = this.context
const { location } = this.props
let targetIndex = _.findIndex(this.notes, (note) => {
return note.storage + '-' + note.key === noteHash
})
let targetIndex = this.getTargetIndex()
if (targetIndex < 0) targetIndex = 0
@@ -233,49 +229,67 @@ class NoteList extends React.Component {
let { data, params, location } = this.props
let { router } = this.context
if (location.pathname.match(/\/home/)) {
return data.noteMap.map((note) => note)
if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) {
const allNotes = data.noteMap.map((note) => note)
this.contextNotes = allNotes
return allNotes
}
if (location.pathname.match(/\/starred/)) {
return data.starredSet.toJS()
.map((uniqueKey) => data.noteMap.get(uniqueKey))
const starredNotes = data.starredSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
this.contextNotes = starredNotes
return starredNotes
}
if (location.pathname.match(/\/searched/)) {
const searchInputText = document.getElementsByClassName('searchInput')[0].value
if (searchInputText === '') {
router.push('/home')
return this.sortByPin(this.contextNotes)
}
return searchFromNotes(this.notes, searchInputText)
return searchFromNotes(this.contextNotes, searchInputText)
}
if (location.pathname.match(/\/trashed/)) {
return data.trashedSet.toJS()
.map((uniqueKey) => data.noteMap.get(uniqueKey))
const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
this.contextNotes = trashedNotes
return trashedNotes
}
let storageKey = params.storageKey
let folderKey = params.folderKey
let storage = data.storageMap.get(storageKey)
if (storage == null) return []
let folder = _.find(storage.folders, {key: folderKey})
if (folder == null) {
let storageNoteSet = data.storageNoteMap
.get(storage.key)
if (storageNoteSet == null) storageNoteSet = []
return storageNoteSet
.map((uniqueKey) => data.noteMap.get(uniqueKey))
if (location.pathname.match(/\/tags/)) {
return data.noteMap.map(note => {
return note
}).filter(note => {
return note.tags.includes(params.tagname)
})
}
let folderNoteKeyList = data.folderNoteMap
.get(storage.key + '-' + folder.key)
return this.getContextNotes()
}
return folderNoteKeyList != null
? folderNoteKeyList
.map((uniqueKey) => data.noteMap.get(uniqueKey))
: []
// get notes in the current folder
getContextNotes () {
const { data, params } = this.props
const storageKey = params.storageKey
const folderKey = params.folderKey
const storage = data.storageMap.get(storageKey)
if (storage === undefined) return []
const folder = _.find(storage.folders, {key: folderKey})
if (folder === undefined) {
const storageNoteSet = data.storageNoteMap.get(storage.key) || []
return storageNoteSet.map((uniqueKey) => data.noteMap.get(uniqueKey))
}
const folderNoteKeyList = data.folderNoteMap.get(`${storage.key}-${folder.key}`) || []
return folderNoteKeyList.map((uniqueKey) => data.noteMap.get(uniqueKey))
}
sortByPin (unorderedNotes) {
const pinnedNotes = unorderedNotes.filter((note) => {
return note.isPinned
})
return pinnedNotes.concat(unorderedNotes)
}
handleNoteClick (e, uniqueKey) {
@@ -319,10 +333,7 @@ class NoteList extends React.Component {
}
alertIfSnippet () {
let { location } = this.props
const targetIndex = _.findIndex(this.notes, (note) => {
return `${note.storage}-${note.key}` === location.query.key
})
const targetIndex = this.getTargetIndex()
if (this.notes[targetIndex].type === 'SNIPPET_NOTE') {
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
@@ -338,6 +349,53 @@ class NoteList extends React.Component {
e.dataTransfer.setData('note', noteData)
}
handleNoteContextMenu (e, uniqueKey) {
const { location } = this.props
const targetIndex = this.getTargetIndex()
let note = this.notes[targetIndex]
const label = note.isPinned ? 'Remove pin' : 'Pin to Top'
let menu = new Menu()
if (!location.pathname.match(/\/home|\/starred|\/trash/)) {
menu.append(new MenuItem({
label: label,
click: (e) => this.pinToTop(e, uniqueKey)
}))
}
menu.append(new MenuItem({
label: 'Delete Note',
click: (e) => this.deleteNote(e, uniqueKey)
}))
menu.popup()
}
pinToTop (e, uniqueKey) {
const { data, params } = this.props
const storageKey = params.storageKey
const folderKey = params.folderKey
const currentStorage = data.storageMap.get(storageKey)
const currentFolder = _.find(currentStorage.folders, {key: folderKey})
const targetIndex = this.getTargetIndex()
let note = this.notes[targetIndex]
note.isPinned = !note.isPinned
dataApi
.updateNote(note.storage, note.key, note)
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
}
deleteNote (e, uniqueKey) {
this.handleNoteClick(e, uniqueKey)
ee.emit('detail:delete')
}
importFromFile () {
const { dispatch, location } = this.props
@@ -364,9 +422,7 @@ class NoteList extends React.Component {
addNotesFromFiles (filepaths) {
const { dispatch, location } = this.props
const targetIndex = _.findIndex(this.notes, (note) => {
return note !== null && `${note.storage}-${note.key}` === location.query.key
})
const targetIndex = this.getTargetIndex()
const storageKey = this.notes[targetIndex].storage
const folderKey = this.notes[targetIndex].folder
@@ -397,6 +453,14 @@ class NoteList extends React.Component {
})
}
getTargetIndex () {
const { location } = this.props
const targetIndex = _.findIndex(this.notes, (note) => {
return `${note.storage}-${note.key}` === location.query.key
})
return targetIndex
}
render () {
let { location, notes, config, dispatch } = this.props
let sortFunc = config.sortBy === 'CREATED_AT'
@@ -404,12 +468,13 @@ class NoteList extends React.Component {
: config.sortBy === 'ALPHABETICAL'
? sortByAlphabetical
: 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
})
const sortedNotes = location.pathname.match(/\/home|\/starred|\/trash/)
? this.getNotes().sort(sortFunc)
: this.sortByPin(this.getNotes().sort(sortFunc))
this.notes = notes = sortedNotes.filter((note) => {
// this is for the trash box
if (note.isTrashed !== true || location.pathname === '/trashed') return true
})
let noteList = notes
.map(note => {
@@ -432,8 +497,10 @@ class NoteList extends React.Component {
note={note}
dateDisplay={dateDisplay}
key={key}
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleNoteClick={this.handleNoteClick.bind(this)}
handleDragStart={this.handleDragStart.bind(this)}
pathname={location.pathname}
/>
)
}
@@ -457,13 +524,13 @@ class NoteList extends React.Component {
>
<div styleName='control'>
<div styleName='control-sortBy'>
<i className='fa fa-bolt' />
<i className='fa fa-angle-down' />
<select styleName='control-sortBy-select'
value={config.sortBy}
onChange={(e) => this.handleSortByChange(e)}
>
<option value='UPDATED_AT'>Last Updated</option>
<option value='CREATED_AT'>Creation Time</option>
<option value='UPDATED_AT'>Updated</option>
<option value='CREATED_AT'>Created</option>
<option value='ALPHABETICAL'>Alphabetically</option>
</select>
</div>

View File

@@ -4,59 +4,81 @@
background-color #f9f9f9
user-select none
color $ui-text-color
height: 100vh
display: flex
flex-direction column
.top
height $topBar-height
padding-bottom 15px
.top-menu
navButtonColor()
height $topBar-height
padding 0 15px
font-size 12px
width 100%
text-align left
position absolute
top 22px
right 5px
height 23px
width 2em
&:hover
color $ui-text-color
&:active, &:active:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
.switch-buttons
background-color transparent
border 1px solid $ui-borderColor
width 110px
height 25px
margin 20px auto 0px auto
border-radius 1px
.non-active-button
navButtonColor()
font-weight 600
width 54px
height 23px
.active-button
@extend .non-active-button
background-color $ui-button--active-backgroundColor
color $ui-text-color
&:hover
background-color alpha($ui-button--active-backgroundColor, 70%)
color alpha($ui-text-color, 70%)
&:active, &:active:hover
background-color $ui-button--active-backgroundColor
.top-menu-label
margin-left 5px
overflow ellipsis
opacity 0
.storageList
absolute left right
bottom 37px
top 160px
.tabBody
flex 1
display flex
flex-direction column
.tag-title
padding-left 15px
padding-bottom 13px
p
color $ui-text-color
.tagList
overflow-y auto
.storageList-empty
padding 0 10px
margin-top 15px
line-height 24px
color $ui-inactive-text-color
.navToggle
navButtonColor()
display block
position absolute
right 5px
bottom 5px
border-radius 16.5px
height 34px
width 34px
line-height 32px
padding 0
flex: 1
.root--folded
@extend .root
width 44px
.storageList-empty
white-space nowrap
transform rotate(90deg)
height 100vh
width $sideNav--folded-width
.switch-buttons
display none
.top
height 60px
.top-menu
width 44px - 1
position static
width $sideNav--folded-width
height 60px
text-align center
&:hover .top-menu-label
transition opacity 0.15s
@@ -65,7 +87,7 @@
position fixed
display inline-block
height 30px
left 32px
left $sideNav--folded-width
padding 0 10px
margin-top -8px
opacity 0
@@ -79,30 +101,6 @@
border-bottom-right-radius 2px
pointer-events none
font-size 12px
.menu-button, .menu-button--active
text-align center
&:hover .menu-button-label
transition opacity 0.15s
opacity 1
.menu-button-label
position fixed
display inline-block
height 32px
left 44px
padding 0 10px
margin-top -8px
margin-left 0
overflow ellipsis
background-color $ui-tooltip-backgroundColor
z-index 10
color white
line-height 32px
border-top-right-radius 2px
border-bottom-right-radius 2px
pointer-events none
opacity 0
font-size 12px
body[data-theme="dark"]
.root, .root--folded
@@ -120,11 +118,26 @@ body[data-theme="dark"]
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
.storageList-empty
color $ui-dark-inactive-text-color
.switch-buttons
border-color $ui-dark-borderColor
.navToggle
.non-active-button
navDarkButtonColor()
.active-button
@extend .non-active-button
background-color $ui-dark-button--active-backgroundColor
color $ui-dark-text-color
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s
color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 70%)
color alpha($ui-dark-text-color, 70%)
&:active
color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 60%)
&:active, &:active:hover
color $ui-dark-text-color
background-color $ui-dark-button--active-backgroundColor
.tag-title
p
color alpha($ui-dark-text-color, 60%)

View File

@@ -5,7 +5,10 @@ import { openModal } from 'browser/main/lib/modal'
import PreferencesModal from '../modals/PreferencesModal'
import ConfigManager from 'browser/main/lib/ConfigManager'
import StorageItem from './StorageItem'
import TagListItem from 'browser/components/TagListItem'
import SideNavFilter from 'browser/components/SideNavFilter'
import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton'
class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7
@@ -38,13 +41,85 @@ class SideNav extends React.Component {
router.push('/trashed')
}
handleSwitchFoldersButtonClick () {
const { router } = this.context
router.push('/home')
}
handleSwitchTagsButtonClick () {
const { router } = this.context
router.push('/alltags')
}
SideNavComponent (isFolded, storageList) {
let { location, data } = this.props
const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/)
const isTrashedActive = !!location.pathname.match(/^\/trashed$/)
let component
// TagsMode is not selected
if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) {
component = (
<div>
<SideNavFilter
isFolded={isFolded}
isHomeActive={isHomeActive}
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
isStarredActive={isStarredActive}
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
/>
<StorageList storageList={storageList} />
<NavToggleButton isFolded={isFolded} handleToggleButtonClick={this.handleToggleButtonClick.bind(this)} />
</div>
)
} else {
component = (
<div styleName='tabBody'>
<div styleName='tag-title'>
<p>Tags</p>
</div>
<div styleName='tagList'>
{this.tagListComponent(data)}
</div>
</div>
)
}
return component
}
tagListComponent () {
const { data, location } = this.props
let tagList = data.tagNoteMap.map((tag, key) => {
return key
})
return (
tagList.map(tag => (
<TagListItem
name={tag}
handleClickTagListItem={this.handleClickTagListItem.bind(this)}
isActive={!!location.pathname.match(tag)}
key={tag}
/>
))
)
}
handleClickTagListItem (name) {
const { router } = this.context
router.push(`/tags/${name}`)
}
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
@@ -58,6 +133,7 @@ class SideNav extends React.Component {
})
let style = {}
if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/)
return (
<div className='SideNav'
styleName={isFolded ? 'root--folded' : 'root'}
@@ -65,37 +141,20 @@ class SideNav extends React.Component {
style={style}
>
<div styleName='top'>
<button styleName='top-menu'
onClick={(e) => this.handleMenuButtonClick(e)}
>
<i className='fa fa-wrench fa-fw' />
<span styleName='top-menu-label'>Preferences</span>
</button>
<div styleName='switch-buttons'>
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>Folders</button>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>Tags</button>
</div>
<div>
<button styleName='top-menu'
onClick={(e) => this.handleMenuButtonClick(e)}
>
<i className='fa fa-wrench fa-fw' />
<span styleName='top-menu-label'>Preferences</span>
</button>
</div>
</div>
<SideNavFilter
isFolded={isFolded}
isHomeActive={isHomeActive}
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
isStarredActive={isStarredActive}
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
/>
<div styleName='storageList'>
{storageList.length > 0 ? storageList : (
<div styleName='storageList-empty'>No storage mount.</div>
)}
</div>
<button styleName='navToggle'
onClick={(e) => this.handleToggleButtonClick(e)}
>
{isFolded
? <i className='fa fa-angle-double-right' />
: <i className='fa fa-angle-double-left' />
}
</button>
{this.SideNavComponent(isFolded, storageList)}
</div>
)
}

View File

@@ -18,7 +18,10 @@ class TopBar extends React.Component {
this.state = {
search: '',
searchOptions: [],
isSearching: false
isSearching: false,
isAlphabet: false,
isIME: false,
isConfirmTranslation: false
}
this.focusSearchHandler = () => {
@@ -34,9 +37,52 @@ class TopBar extends React.Component {
ee.off('top:focus-search', this.focusSearchHandler)
}
handleKeyDown (e) {
// reset states
this.setState({
isAlphabet: false,
isIME: false
})
// When the key is an alphabet, del, enter or ctr
if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) {
this.setState({
isAlphabet: true
})
// When the key is an IME input (Japanese, Chinese)
} else if (e.keyCode === 229) {
this.setState({
isIME: true
})
}
}
handleKeyUp (e) {
const { router } = this.context
// reset states
this.setState({
isConfirmTranslation: false
})
// When the key is translation confirmation (Enter, Space)
if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) {
this.setState({
isConfirmTranslation: true
})
router.push('/searched')
this.setState({
search: this.refs.searchInput.value
})
}
}
handleSearchChange (e) {
let { router } = this.context
router.push('/searched')
const { router } = this.context
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
router.push('/searched')
} else {
e.preventDefault()
}
this.setState({
search: this.refs.searchInput.value
})
@@ -93,6 +139,8 @@ class TopBar extends React.Component {
ref='searchInput'
value={this.state.search}
onChange={(e) => this.handleSearchChange(e)}
onKeyDown={(e) => this.handleKeyDown(e)}
onKeyUp={(e) => this.handleKeyUp(e)}
placeholder='Search'
type='text'
className='searchInput'

View File

@@ -102,3 +102,10 @@ body[data-theme="dark"]
background #B1D7FE
::selection
background #B1D7FE
.sortableItemHelper
z-index modalZIndex + 5
body[data-theme="dark"]
.sortableItemHelper
color: $ui-dark-text-color

View File

@@ -27,7 +27,10 @@ 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')
const offsetParent = e.target.offsetParent
const isInfoPanel = offsetParent !== null
? offsetParent.className.includes('infoPanel')
: false
if (isInfoButton || isInfoPanel) return
const infoPanel = document.querySelector('.infoPanel')
if (infoPanel) infoPanel.style.display = 'none'
@@ -62,6 +65,11 @@ ReactDOM.render((
<Route path='starred' />
<Route path='searched' />
<Route path='trashed' />
<Route path='alltags' />
<Route path='tags'>
<IndexRedirect to='/alltags' />
<Route path=':tagname' />
</Route>
<Route path='storages'>
<IndexRedirect to='/home' />
<Route path=':storageKey'>

View File

@@ -2,17 +2,37 @@ const AWS = require('aws-sdk')
const AMA = require('aws-sdk-mobile-analytics')
const ConfigManager = require('browser/main/lib/ConfigManager')
const remote = require('electron').remote
const os = require('os')
AWS.config.region = 'us-east-1'
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
})
const validPlatformName = convertPlatformName(os.platform())
const mobileAnalyticsClient = new AMA.Manager({
appId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appTitle: 'xxxxxxxxxx'
appTitle: 'xxxxxxxxxx',
appVersionName: remote.app.getVersion().toString(),
platform: validPlatformName
})
}
function convertPlatformName (platformName) {
if (platformName === 'darwin') {
return 'MacOS'
} else if (platformName === 'win32') {
return 'Windows'
} else if (platformName === 'linux') {
return 'Linux'
} else {
return ''
}
}
function initAwsMobileAnalytics () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
AWS.config.credentials.get((err) => {
@@ -24,16 +44,28 @@ function initAwsMobileAnalytics () {
})
}
function recordDynamicCustomEvent (type) {
function recordDynamicCustomEvent (type, options = {}) {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
mobileAnalyticsClient.recordEvent(type)
try {
mobileAnalyticsClient.recordEvent(type, options)
} catch (analyticsError) {
if (analyticsError instanceof ReferenceError) {
console.log(analyticsError.name + ': ' + analyticsError.message)
}
}
}
function recordStaticCustomEvent () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
uiColorTheme: ConfigManager.default.get().ui.theme
})
try {
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
uiColorTheme: ConfigManager.default.get().ui.theme
})
} catch (analyticsError) {
if (analyticsError instanceof ReferenceError) {
console.log(analyticsError.name + ': ' + analyticsError.message)
}
}
}
module.exports = {

View File

@@ -25,6 +25,7 @@ export const DEFAULT_CONFIG = {
},
ui: {
theme: 'default',
showCopyNotification: true,
disableDirectWrite: false,
defaultNote: 'ALWAYS_ASK' // 'ALWAYS_ASK', 'SNIPPET_NOTE', 'MARKDOWN_NOTE'
},

View File

@@ -6,6 +6,7 @@ const dataApi = {
createFolder: require('./createFolder'),
updateFolder: require('./updateFolder'),
deleteFolder: require('./deleteFolder'),
reorderFolder: require('./reorderFolder'),
createNote: require('./createNote'),
updateNote: require('./updateNote'),
deleteNote: require('./deleteNote'),

View File

@@ -0,0 +1,43 @@
const _ = require('lodash')
_.move = require('lodash-move').default
const path = require('path')
const resolveStorageData = require('./resolveStorageData')
const CSON = require('@rokt33r/season')
const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} storageKey
* @param {number} oldIndex
* @param {number} newIndex
*
* @return {Object}
* ```
* {
* storage: Object
* }
* ```
*/
function reorderFolder (storageKey, oldIndex, newIndex) {
let rawStorages
let targetStorage
try {
if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')
if (!_.isNumber(newIndex)) throw new Error('newIndex must be a number.')
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
return resolveStorageData(targetStorage)
.then(function reorderFolder (storage) {
storage.folders = _.move(storage.folders, oldIndex, newIndex)
CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version']))
return {
storage
}
})
}
module.exports = reorderFolder

View File

@@ -2,6 +2,7 @@ const _ = require('lodash')
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 updateFolder (storageKey, folderKey, 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

@@ -26,6 +26,10 @@ function validateInput (input) {
validatedInput.isTrashed = !!input.isTrashed
}
if (input.isPinned !== undefined) {
validatedInput.isPinned = !!input.isPinned
}
validatedInput.type = input.type
switch (input.type) {
case 'MARKDOWN_NOTE':
@@ -104,6 +108,7 @@ function updateNote (storageKey, noteKey, input) {
noteData.isStarred = false
noteData.isTrashed = false
noteData.tags = []
noteData.isPinned = false
}
if (noteData.type === 'SNIPPET_NOTE') {

View File

@@ -152,7 +152,7 @@ class InitModal extends React.Component {
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```'
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 or registration required. \n- [ ] Quick search and copy the content of note. macOS: <kbd>Cmd</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> / windows: <kbd>Ctrl</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> \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({
@@ -194,13 +194,13 @@ class InitModal extends React.Component {
return (
<div styleName='root'
tabIndex='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
onKeyDown={this.props.close}
>
<div styleName='header'>
<div styleName='header-title'>Initialize Storage</div>
</div>
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
<ModalEscButton handleEscButtonClick={this.props.close} />
<div styleName='body'>
<div styleName='body-welcome'>
Welcome!

View File

@@ -67,10 +67,17 @@
text-align right
:global
.alert
font-size 12px
line-height 30px
padding 0 5px
float right
display inline-block
position absolute
top 60px
right 15px
font-size 14px
.success
color green
.error
color red
.group-control-leftButton
colorDefaultButton()

View File

@@ -0,0 +1,49 @@
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './Crowdfunding.styl'
const electron = require('electron')
const { shell } = electron
class Crowdfunding extends React.Component {
constructor (props) {
super(props)
this.state = {
}
}
handleLinkClick (e) {
shell.openExternal(e.currentTarget.href)
e.preventDefault()
}
render () {
return (
<div styleName='root'>
<div styleName='header'>Crowdfunding</div>
<p>Dear all,</p>
<br />
<p>Thanks for your using!</p>
<p>Boostnote is used in about 200 countries and regions, it is a awesome developer community.</p>
<br />
<p>To continue supporting this growth, and to satisfy community expectations,</p>
<p>we would like to invest more time in this project.</p>
<br />
<p>If you like this project and see its potential, you can help!</p>
<br />
<p>Thanks,</p>
<p>Boostnote maintainers.</p>
<br />
<button styleName='cf-link'>
<a href='https://opencollective.com/boostnoteio' onClick={(e) => this.handleLinkClick(e)}>Support via OpenCollective</a>
</button>
</div>
)
}
}
Crowdfunding.propTypes = {
}
export default CSSModules(Crowdfunding, styles)

View File

@@ -0,0 +1,30 @@
@import('./Tab')
.root
padding 15px
white-space pre
line-height 1.4
color alpha($ui-text-color, 90%)
width 100%
font-size 14px
p
font-size 16px
.cf-link
width 250px
height 35px
border-radius 2px
border none
background-color alpha(#1EC38B, 90%)
&:hover
background-color #1EC38B
transition 0.2s
a
text-decoration none
color white
font-weight 600
font-size 16px
body[data-theme="dark"]
p
color $ui-dark-text-color

View File

@@ -0,0 +1,303 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import ReactDOM from 'react-dom'
import styles from './FolderItem.styl'
import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
import { SketchPicker } from 'react-color'
import { SortableElement, SortableHandle } from 'react-sortable-hoc'
class FolderItem extends React.Component {
constructor (props) {
super(props)
this.state = {
status: 'IDLE',
folder: {
showColumnPicker: false,
colorPickerPos: { left: 0, top: 0 },
color: props.color,
name: props.name
}
}
}
handleEditChange (e) {
let { folder } = this.state
folder.name = this.refs.nameInput.value
this.setState({
folder
})
}
handleConfirmButtonClick (e) {
this.confirm()
}
confirm () {
let { storage, folder } = this.props
dataApi
.updateFolder(storage.key, folder.key, {
color: this.state.folder.color,
name: this.state.folder.name
})
.then((data) => {
store.dispatch({
type: 'UPDATE_FOLDER',
storage: data.storage
})
this.setState({
status: 'IDLE'
})
})
}
handleColorButtonClick (e) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
this.setState({ folder }, function () {
// After the color picker has been painted, re-calculate its position
// by comparing its dimensions to the host dimensions.
const { hostBoundingBox } = this.props
const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
const colorPickerBox = colorPickerNode.getBoundingClientRect()
const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
const folder = Object.assign({}, this.state.folder, {
colorPickerPos: {
left: 25,
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
}
})
this.setState({ folder })
})
}
handleColorChange (color) {
const folder = Object.assign({}, this.state.folder, { color: color.hex })
this.setState({ folder })
}
handleColorPickerClose (event) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
this.setState({ folder })
}
handleCancelButtonClick (e) {
this.setState({
status: 'IDLE'
})
}
handleFolderItemBlur (e) {
let el = e.relatedTarget
while (el != null) {
if (el === this.refs.root) {
return false
}
el = el.parentNode
}
this.confirm()
}
renderEdit (e) {
const popover = { position: 'absolute', zIndex: 2 }
const cover = {
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0
}
const pickerStyle = Object.assign({}, {
position: 'absolute'
}, this.state.folder.colorPickerPos)
return (
<div styleName='folderItem'
onBlur={(e) => this.handleFolderItemBlur(e)}
tabIndex='-1'
ref='root'
>
<div styleName='folderItem-left'>
<button styleName='folderItem-left-colorButton' style={{color: this.state.folder.color}}
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
>
{this.state.folder.showColumnPicker
? <div style={popover}>
<div style={cover}
onClick={() => this.handleColorPickerClose()}
/>
<div style={pickerStyle}>
<SketchPicker
ref='colorPicker'
color={this.state.folder.color}
onChange={(color) => this.handleColorChange(color)}
onChangeComplete={(color) => this.handleColorChange(color)}
/>
</div>
</div>
: null
}
<i className='fa fa-square' />
</button>
<input styleName='folderItem-left-nameInput'
value={this.state.folder.name}
ref='nameInput'
onChange={(e) => this.handleEditChange(e)}
/>
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-confirmButton'
onClick={(e) => this.handleConfirmButtonClick(e)}
>
Confirm
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
Cancel
</button>
</div>
</div>
)
}
handleDeleteConfirmButtonClick (e) {
let { storage, folder } = this.props
dataApi
.deleteFolder(storage.key, folder.key)
.then((data) => {
store.dispatch({
type: 'DELETE_FOLDER',
storage: data.storage,
folderKey: data.folderKey
})
})
}
renderDelete () {
return (
<div styleName='folderItem'>
<div styleName='folderItem-left'>
Are you sure to <span styleName='folderItem-left-danger'>delete</span> this folder?
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-dangerButton'
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
>
Confirm
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
Cancel
</button>
</div>
</div>
)
}
handleEditButtonClick (e) {
let { folder: propsFolder } = this.props
let { folder: stateFolder } = this.state
const folder = Object.assign({}, stateFolder, propsFolder)
this.setState({
status: 'EDIT',
folder
}, () => {
this.refs.nameInput.select()
})
}
handleDeleteButtonClick (e) {
this.setState({
status: 'DELETE'
})
}
renderIdle () {
let { folder } = this.props
return (
<div styleName='folderItem'
onDoubleClick={(e) => this.handleEditButtonClick(e)}
>
<div styleName='folderItem-left'
style={{borderColor: folder.color}}
>
<span styleName='folderItem-left-name'>{folder.name}</span>
<span styleName='folderItem-left-key'>({folder.key})</span>
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleEditButtonClick(e)}
>
Edit
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleDeleteButtonClick(e)}
>
Delete
</button>
</div>
</div>
)
}
render () {
switch (this.state.status) {
case 'DELETE':
return this.renderDelete()
case 'EDIT':
return this.renderEdit()
case 'IDLE':
default:
return this.renderIdle()
}
}
}
FolderItem.propTypes = {
hostBoundingBox: PropTypes.shape({
bottom: PropTypes.number,
height: PropTypes.number,
left: PropTypes.number,
right: PropTypes.number,
top: PropTypes.number,
width: PropTypes.number
}),
storage: PropTypes.shape({
key: PropTypes.string
}),
folder: PropTypes.shape({
key: PropTypes.string,
color: PropTypes.string,
name: PropTypes.string
})
}
class Handle extends React.Component {
render () {
return (
<div styleName='folderItem-drag-handle'>
<i className='fa fa-reorder' />
</div>
)
}
}
class SortableFolderItemComponent extends React.Component {
render () {
const StyledHandle = CSSModules(Handle, this.props.styles)
const DragHandle = SortableHandle(StyledHandle)
const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
return (
<div>
<DragHandle />
<StyledFolderItem {...this.props} />
</div>
)
}
}
export default CSSModules(SortableElement(SortableFolderItemComponent), styles)

View File

@@ -0,0 +1,103 @@
.folderItem
height 35px
box-sizing border-box
padding 2.5px 15px
&:hover
background-color darken(white, 3%)
.folderItem-drag-handle
height 35px
border none
padding 0 10px
line-height 35px
float left
cursor row-resize
.folderItem-left
height 30px
border-left solid 2px transparent
padding 0 10px
line-height 30px
float left
.folderItem-left-danger
color $danger-color
font-weight bold
.folderItem-left-key
color $ui-inactive-text-color
font-size 10px
margin 0 5px
border none
.folderItem-left-colorButton
colorDefaultButton()
height 25px
width 25px
line-height 23px
padding 0
box-sizing border-box
vertical-align middle
border $ui-border
border-radius 2px
margin-right 5px
margin-left -15px
.folderItem-left-nameInput
height 25px
box-sizing border-box
vertical-align middle
border $ui-border
border-radius 2px
padding 0 5px
outline none
.folderItem-right
float right
.folderItem-right-button
vertical-align middle
height 25px
margin-top 2.5px
colorDefaultButton()
border-radius 2px
border $ui-border
margin-right 5px
padding 0 5px
&:last-child
margin-right 0
.folderItem-right-confirmButton
@extend .folderItem-right-button
border none
colorPrimaryButton()
.folderItem-right-dangerButton
@extend .folderItem-right-button
border none
colorDangerButton()
body[data-theme="dark"]
.folderItem
&:hover
background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
.folderItem-left-danger
color $danger-color
font-weight bold
.folderItem-left-key
color $ui-dark-inactive-text-color
.folderItem-left-colorButton
colorDarkDefaultButton()
border-color $ui-dark-borderColor
.folderItem-right-button
colorDarkDefaultButton()
border-color $ui-dark-borderColor
.folderItem-right-confirmButton
colorDarkPrimaryButton()
.folderItem-right-dangerButton
colorDarkDangerButton()

View File

@@ -0,0 +1,84 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import dataApi from 'browser/main/lib/dataApi'
import styles from './FolderList.styl'
import store from 'browser/main/store'
import FolderItem from './FolderItem'
import { SortableContainer, arrayMove } from 'react-sortable-hoc'
class FolderList extends React.Component {
render () {
let { storage, hostBoundingBox } = this.props
let folderList = storage.folders.map((folder, index) => {
return <FolderItem key={folder.key}
folder={folder}
storage={storage}
index={index}
hostBoundingBox={hostBoundingBox}
/>
})
return (
<div styleName='folderList'>
{folderList.length > 0
? folderList
: <div styleName='folderList-empty'>No Folders</div>
}
</div>
)
}
}
FolderList.propTypes = {
hostBoundingBox: PropTypes.shape({
bottom: PropTypes.number,
height: PropTypes.number,
left: PropTypes.number,
right: PropTypes.number,
top: PropTypes.number,
width: PropTypes.number
}),
storage: PropTypes.shape({
key: PropTypes.string
}),
folder: PropTypes.shape({
key: PropTypes.number,
color: PropTypes.string,
name: PropTypes.string
})
}
class SortableFolderListComponent extends React.Component {
constructor (props) {
super(props)
this.onSortEnd = ({oldIndex, newIndex}) => {
let { storage } = this.props
dataApi
.reorderFolder(storage.key, oldIndex, newIndex)
.then((data) => {
store.dispatch({
type: 'REORDER_FOLDER',
storage: data.storage
})
this.setState()
})
}
}
render () {
const StyledFolderList = CSSModules(FolderList, this.props.styles)
const SortableFolderList = SortableContainer(StyledFolderList)
return (
<SortableFolderList
helperClass='sortableItemHelper'
onSortEnd={this.onSortEnd}
useDragHandle
{...this.props}
/>
)
}
}
export default CSSModules(SortableFolderListComponent, styles)

View File

@@ -3,6 +3,7 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './ConfigTab.styl'
import ConfigManager from 'browser/main/lib/ConfigManager'
import store from 'browser/main/store'
import _ from 'lodash'
const electron = require('electron')
const ipc = electron.ipcRenderer
@@ -50,6 +51,7 @@ class HotkeyTab extends React.Component {
type: 'SET_UI',
config: newConfig
})
this.clearMessage()
}
handleHintToggleButtonClick (e) {
@@ -69,6 +71,14 @@ class HotkeyTab extends React.Component {
})
}
clearMessage () {
_.debounce(() => {
this.setState({
keymapAlert: null
})
}, 2000)()
}
render () {
let keymapAlert = this.state.keymapAlert
let keymapAlertElement = keymapAlert != null
@@ -94,7 +104,7 @@ class HotkeyTab extends React.Component {
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>Toggle Finder(popup)</div>
<div styleName='group-section-label'>Toggle Finder (Quick search)</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
onChange={(e) => this.handleHotkeyChange(e)}

View File

@@ -74,9 +74,9 @@ class InfoTab extends React.Component {
>Boostnote Shop</a> : Products are shipped to all over the world 🌏
</li>
<li>
<a href='https://salt.bountysource.com/teams/boostnote'
<a href='https://opencollective.com/boostnoteio'
onClick={(e) => this.handleLinkClick(e)}
>Donate via Bountysource</a> : Thank you for your support 🎉
>Crowdfunding</a> : Thank you for your support 🎉
</li>
<li>
<a href='https://github.com/BoostIO/Boostnote/issues'
@@ -99,7 +99,7 @@ class InfoTab extends React.Component {
<div styleName='policy'>Data collection policy</div>
<div>We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.</div>
<div>You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
<div>These data are only used for Boostnote improvements.</div>
<div>This data is only used for Boostnote improvements.</div>
<input onChange={(e) => this.handleConfigChange(e)}
checked={this.state.config.amaEnabled}
ref='amaEnabled'

View File

@@ -25,7 +25,7 @@ top-bar--height = 50px
absolute top left right
top top-bar--height
left 0
width 140px
width 170px
margin-left 10px
margin-top 20px
background-color $ui-backgroundColor
@@ -33,7 +33,7 @@ top-bar--height = 50px
.nav-button
font-size 14px
text-align left
width 120px
width 150px
margin 5px 0
padding 7px 0
padding-left 10px
@@ -56,7 +56,7 @@ top-bar--height = 50px
.content
absolute left right bottom
top top-bar--height
left 140px
left 170px
margin-top 10px
overflow-y auto

View File

@@ -1,265 +1,13 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageItem.styl'
import consts from 'browser/lib/consts'
import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
import FolderList from './FolderList'
const { shell, remote } = require('electron')
const { dialog } = remote
import { SketchPicker } from 'react-color'
class UnstyledFolderItem extends React.Component {
constructor (props) {
super(props)
this.state = {
status: 'IDLE',
folder: {
showColumnPicker: false,
colorPickerPos: { left: 0, top: 0 },
color: props.color,
name: props.name
}
}
}
handleEditChange (e) {
let { folder } = this.state
folder.name = this.refs.nameInput.value
this.setState({
folder
})
}
handleConfirmButtonClick (e) {
this.confirm()
}
confirm () {
let { storage, folder } = this.props
dataApi
.updateFolder(storage.key, folder.key, {
color: this.state.folder.color,
name: this.state.folder.name
})
.then((data) => {
store.dispatch({
type: 'UPDATE_FOLDER',
storage: data.storage
})
this.setState({
status: 'IDLE'
})
})
}
handleColorButtonClick (e) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
this.setState({ folder }, function () {
// After the color picker has been painted, re-calculate its position
// by comparing its dimensions to the host dimensions.
const { hostBoundingBox } = this.props
const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
const colorPickerBox = colorPickerNode.getBoundingClientRect()
const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
const folder = Object.assign({}, this.state.folder, {
colorPickerPos: {
left: 25,
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
}
})
this.setState({ folder })
})
}
handleColorChange (color) {
const folder = Object.assign({}, this.state.folder, { color: color.hex })
this.setState({ folder })
}
handleColorPickerClose (event) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
this.setState({ folder })
}
handleCancelButtonClick (e) {
this.setState({
status: 'IDLE'
})
}
handleFolderItemBlur (e) {
let el = e.relatedTarget
while (el != null) {
if (el === this.refs.root) {
return false
}
el = el.parentNode
}
this.confirm()
}
renderEdit (e) {
const popover = { position: 'absolute', zIndex: 2 }
const cover = {
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0
}
const pickerStyle = Object.assign({}, {
position: 'absolute'
}, this.state.folder.colorPickerPos)
return (
<div styleName='folderList-item'
onBlur={(e) => this.handleFolderItemBlur(e)}
tabIndex='-1'
ref='root'
>
<div styleName='folderList-item-left'>
<button styleName='folderList-item-left-colorButton' style={{color: this.state.folder.color}}
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
>
{this.state.folder.showColumnPicker
? <div style={popover}>
<div style={cover}
onClick={() => this.handleColorPickerClose()}
/>
<div style={pickerStyle}>
<SketchPicker
ref='colorPicker'
color={this.state.folder.color}
onChange={(color) => this.handleColorChange(color)}
onChangeComplete={(color) => this.handleColorChange(color)}
/>
</div>
</div>
: null
}
<i className='fa fa-square' />
</button>
<input styleName='folderList-item-left-nameInput'
value={this.state.folder.name}
ref='nameInput'
onChange={(e) => this.handleEditChange(e)}
/>
</div>
<div styleName='folderList-item-right'>
<button styleName='folderList-item-right-confirmButton'
onClick={(e) => this.handleConfirmButtonClick(e)}
>
Confirm
</button>
<button styleName='folderList-item-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
Cancel
</button>
</div>
</div>
)
}
handleDeleteConfirmButtonClick (e) {
let { storage, folder } = this.props
dataApi
.deleteFolder(storage.key, folder.key)
.then((data) => {
store.dispatch({
type: 'DELETE_FOLDER',
storage: data.storage,
folderKey: data.folderKey
})
})
}
renderDelete () {
return (
<div styleName='folderList-item'>
<div styleName='folderList-item-left'>
Are you sure to <span styleName='folderList-item-left-danger'>delete</span> this folder?
</div>
<div styleName='folderList-item-right'>
<button styleName='folderList-item-right-dangerButton'
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
>
Confirm
</button>
<button styleName='folderList-item-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
Cancel
</button>
</div>
</div>
)
}
handleEditButtonClick (e) {
let { folder: propsFolder } = this.props
let { folder: stateFolder } = this.state
const folder = Object.assign({}, stateFolder, propsFolder)
this.setState({
status: 'EDIT',
folder
}, () => {
this.refs.nameInput.select()
})
}
handleDeleteButtonClick (e) {
this.setState({
status: 'DELETE'
})
}
renderIdle () {
let { folder } = this.props
return (
<div styleName='folderList-item'
onDoubleClick={(e) => this.handleEditButtonClick(e)}
>
<div styleName='folderList-item-left'
style={{borderColor: folder.color}}
>
<span styleName='folderList-item-left-name'>{folder.name}</span>
<span styleName='folderList-item-left-key'>({folder.key})</span>
</div>
<div styleName='folderList-item-right'>
<button styleName='folderList-item-right-button'
onClick={(e) => this.handleEditButtonClick(e)}
>
Edit
</button>
<button styleName='folderList-item-right-button'
onClick={(e) => this.handleDeleteButtonClick(e)}
>
Delete
</button>
</div>
</div>
)
}
render () {
switch (this.state.status) {
case 'DELETE':
return this.renderDelete()
case 'EDIT':
return this.renderEdit()
case 'IDLE':
default:
return this.renderIdle()
}
}
}
const FolderItem = CSSModules(UnstyledFolderItem, styles)
class StorageItem extends React.Component {
constructor (props) {
@@ -349,13 +97,7 @@ class StorageItem extends React.Component {
render () {
let { storage, hostBoundingBox } = this.props
let folderList = storage.folders.map((folder) => {
return <FolderItem key={folder.key}
folder={folder}
storage={storage}
hostBoundingBox={hostBoundingBox}
/>
})
return (
<div styleName='root' key={storage.key}>
<div styleName='header'>
@@ -404,12 +146,9 @@ class StorageItem extends React.Component {
</button>
</div>
</div>
<div styleName='folderList'>
{folderList.length > 0
? folderList
: <div styleName='folderList-empty'>No Folders</div>
}
</div>
<FolderList storage={storage}
hostBoundingBox={hostBoundingBox}
/>
</div>
)
}
@@ -426,11 +165,6 @@ StorageItem.propTypes = {
}),
storage: PropTypes.shape({
key: PropTypes.string
}),
folder: PropTypes.shape({
key: PropTypes.string,
color: PropTypes.string,
name: PropTypes.string
})
}

View File

@@ -63,75 +63,6 @@
z-index 10
white-space nowrap
.folderList-item
height 35px
box-sizing border-box
padding 2.5px 15px
&:hover
background-color darken(white, 3%)
.folderList-item-left
height 30px
border-left solid 2px transparent
padding 0 10px
line-height 30px
float left
.folderList-item-left-danger
color $danger-color
font-weight bold
.folderList-item-left-key
color $ui-inactive-text-color
font-size 10px
margin 0 5px
border none
.folderList-item-left-colorButton
colorDefaultButton()
height 25px
width 25px
line-height 23px
padding 0
box-sizing border-box
vertical-align middle
border $ui-border
border-radius 2px
margin-right 5px
margin-left -15px
.folderList-item-left-nameInput
height 25px
box-sizing border-box
vertical-align middle
border $ui-border
border-radius 2px
padding 0 5px
outline none
.folderList-item-right
float right
.folderList-item-right-button
vertical-align middle
height 25px
margin-top 2.5px
colorDefaultButton()
border-radius 2px
border $ui-border
margin-right 5px
padding 0 5px
&:last-child
margin-right 0
.folderList-item-right-confirmButton
@extend .folderList-item-right-button
border none
colorPrimaryButton()
.folderList-item-right-dangerButton
@extend .folderList-item-right-button
border none
colorDangerButton()
body[data-theme="dark"]
.header
border-color $ui-dark-borderColor
@@ -153,28 +84,3 @@ body[data-theme="dark"]
top 25px
z-index 10
white-space nowrap
.folderList-item
&:hover
background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
.folderList-item-left-danger
color $danger-color
font-weight bold
.folderList-item-left-key
color $ui-dark-inactive-text-color
.folderList-item-left-colorButton
colorDarkDefaultButton()
border-color $ui-dark-borderColor
.folderList-item-right-button
colorDarkDefaultButton()
border-color $ui-dark-borderColor
.folderList-item-right-confirmButton
colorDarkPrimaryButton()
.folderList-item-right-dangerButton
colorDarkDangerButton()

View File

@@ -36,6 +36,7 @@ class UiTab extends React.Component {
const newConfig = {
ui: {
theme: this.refs.uiTheme.value,
showCopyNotification: this.refs.showCopyNotification.checked,
disableDirectWrite: this.refs.uiD2w != null
? this.refs.uiD2w.checked
: false
@@ -60,7 +61,7 @@ class UiTab extends React.Component {
const newCodemirrorTheme = this.refs.editorTheme.value
if (newCodemirrorTheme !== codemirrorTheme) {
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme}.css`)
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`)
}
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme })
@@ -102,6 +103,16 @@ class UiTab extends React.Component {
</select>
</div>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.showCopyNotification}
ref='showCopyNotification'
type='checkbox'
/>&nbsp;
Show &quot;Saved to Clipboard&quot; notification when copying
</label>
</div>
{
global.process.platform === 'win32'
? <div styleName='group-checkBoxSection'>

View File

@@ -4,6 +4,7 @@ import { connect } from 'react-redux'
import HotkeyTab from './HotkeyTab'
import UiTab from './UiTab'
import InfoTab from './InfoTab'
import Crowdfunding from './Crowdfunding'
import StoragesTab from './StoragesTab'
import ModalEscButton from 'browser/components/ModalEscButton'
import CSSModules from 'browser/lib/CSSModules'
@@ -64,6 +65,10 @@ class Preferences extends React.Component {
config={config}
/>
)
case 'CROWDFUNDING':
return (
<Crowdfunding />
)
case 'STORAGES':
default:
return (
@@ -94,7 +99,8 @@ class Preferences extends React.Component {
{target: 'STORAGES', label: 'Storages'},
{target: 'HOTKEY', label: 'Hotkey'},
{target: 'UI', label: 'UI'},
{target: 'INFO', label: 'Info'}
{target: 'INFO', label: 'Info'},
{target: 'CROWDFUNDING', label: 'Crowdfunding'}
]
let navButtons = tabs.map((tab) => {

View File

@@ -346,6 +346,13 @@ function data (state = defaultDataMap(), action) {
state.storageMap.set(action.storage.key, action.storage)
}
return state
case 'REORDER_FOLDER':
{
state = Object.assign({}, state)
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
}
return state
case 'DELETE_FOLDER':
{
state = Object.assign({}, state)

View File

@@ -5,7 +5,7 @@ This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/b
* npm: 4.x
* node: 7.x
You should use `npm v4.x` because `$ grand pre-build` fails on `v5.x`.
You should use `npm v4.x` because `$ grunt pre-build` fails on `v5.x`.
## Development

View File

@@ -1,5 +1,5 @@
# How to debug Boostnote (Electron app)
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.

View File

@@ -1,43 +1,49 @@
# Build
## 환경
* npm: 4.x
* node: 7.x
`$ grunt pre-build``npm v5.x`에서 실행할 수 없기 때문에, 반드시 `npm v4.x`를 사용하셔야 합니다.
## 개발
Webpack HRM을 개발을 위해 사용합니다.
다음 명령을 통해 저희가 해둔 설정을 사용 할 수 있습니다.
개발에 있어서 Webpack HRM을 사용합니다.
다음과 같은 명령을 프로젝트 디렉토리에서 실행하면, 기본 설정을 사용 할 수 있습니다.
먼저, yarn을 이용해서 필요한 패키지들을 설치합니다.
```
yarn run webpack
$ yarn
```
몇 초 후, 다음 메세지를 보게 될겁니다.
그 다음, 아래의 명령으로 빌드를 끝내고 자동적으로 어플리케이션을 실행합니다.
```
webpack: bundle is now VALID.
$ yarn run dev-start
```
그럼 앱을 실행합시다.
이 명령은 `yarn run webpack``yarn run hot`을 동시에 실행합니다. 이는 두개의 터미널에서 각각의 명령을 동시에 실행하는 것과 같습니다.
```
yarn run hot
```
`Webpack`은 코드의 변화를 자동으로 탐지하여 적용시키는 역할을 합니다.
> 원래 앱은 `yarn start`로 실행가능합니다. 하지만 이 경우, 컴파일된 스크립트를 사용할 것입니다.
만약, `Failed to load resource: net::ERR_CONNECTION_REFUSED`과 같은 에러가 나타난다면 Boostnote를 리로드해주세요.
이로써 웹팩이 자동적으로 코드변경을 확인하고 적용해줄 것입니다.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### 주의
> 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다.
> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우
> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우
> 2. 새로운 CSS코드를 추가할 경우(1.과 같은 이유: CSS클래스는 콤포넌트마다 다시 만들어 지는데, 이 작업은 컨스트럭터에서 일어납니다.)
## 배포
그런트를 사용합니다.
실제 디플로이`grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
Boostnote에서는 배포 자동화를 위하여 그런트를 사용합니다.
실제 배포`grunt`로 실행할 수 있습니다. 하지만, 여기엔 Codesign과 Authenticode의 과정이 포함되어있기 때문에 사용 하셔선 안됩니다.
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
이 빌드는 npm v5.3.0에서는 작동하지 않습니다. 그러므로, 성공적으로 빌드하기 위해서는 v5.2.0을 사용해야 합니다.
```
grunt pre-build

21
docs/ko/debug.md Normal file
View File

@@ -0,0 +1,21 @@
# Boostnote의 디버그 방법(Electron app)
Boostnote는 Electron 애플리케이션이므로 Chromium위에서 작동합니다. 그렇기 때문에 개발자분들은 Google Chrome 브라우저에서 처럼 `Developer Tools`를 사용하실 수 있습니다.
다음과 같이 `Developer Tools`를 실행할 수 있습니다:
![how_to_toggle_devTools](https://cloud.githubusercontent.com/assets/11307908/24343585/162187e2-127c-11e7-9c01-23578db03ecf.png)
`Developer Tools`는 다음과 같이 나타납니다:
![Developer_Tools](https://cloud.githubusercontent.com/assets/11307908/24343545/eff9f3a6-127b-11e7-94cf-cb67bfda634a.png)
에러가 발생할 때에는, 에러메시지가 `console`위에 표시 됩니다.
## 디버깅
예를들면 `debugger`를 사용하여 코드 안에서 다음과 같이 일시 정지지점을 설정할 수 있습니다:
![debugger](https://cloud.githubusercontent.com/assets/11307908/24343879/9459efea-127d-11e7-9943-f60bf7f66d4a.png)
이는 단순한 하나의 예시에 불과합니다. 자기자신에게 가장 잘 맞는 디버그 방법을 찾는 것도 좋을 것 입니다.
## 참고
* [디버그에 관한 Google Chrome의 공식 문서](https://developer.chrome.com/devtools)

View File

@@ -4,7 +4,7 @@
* npm: 4.x
* node: 7.x
Вы должны использовать `npm v4.x`, так как `$ grand pre-build` не работает в `v5.x`.
Вы должны использовать `npm v4.x`, так как `$ grunt pre-build` не работает в `v5.x`.
## Разработка

View File

@@ -4,7 +4,7 @@
* npm: 4.x
* node: 7.x
因为`$ grand pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x`
因为`$ grunt pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x`
## 开发

View File

@@ -1,7 +1,7 @@
{
"name": "boost",
"productName": "Boostnote",
"version": "0.8.15",
"version": "0.8.16",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -61,14 +61,17 @@
"js-sequence-diagrams": "^1000000.0.6",
"katex": "^0.7.1",
"lodash": "^4.11.1",
"lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0",
"markdown-it-imsize": "^2.0.1",
"markdown-it-kbd": "^1.1.0",
"markdown-it-multimd-table": "^2.0.1",
"markdown-it-named-headers": "^0.0.4",
"md5": "^2.0.0",
"mdurl": "^1.0.1",
"mixpanel": "^0.4.1",
"moment": "^2.10.3",
"node-ipc": "^8.1.0",
@@ -77,6 +80,7 @@
"react-codemirror": "^0.3.0",
"react-dom": "^15.0.2",
"react-redux": "^4.4.5",
"react-sortable-hoc": "^0.6.7",
"redux": "^3.5.2",
"sander": "^0.5.1",
"striptags": "^2.2.1",

View File

@@ -21,13 +21,13 @@ New:zap:
[Great contributors](https://github.com/BoostIO/Boostnote/graphs/contributors) :tada:
## 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/t/boostnote-group/shared_invite/enQtMjQ0MjYxNTMxNjY5LTI0NWFkZDEyYWYxYWE0YTMyYjI4NzA2YjBlNmFmOGVhNGFjY2I1MTNmZWJjYmMxYTdkM2VjNWNjYTFiYWQ3ZmQ)
Let's talk about Boostnote! <br>
[Join us](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjU5NTUwNjcwMjkyLWI3N2I1YWIzNWRlZDZmZjVlYzRiNDc1YTcxZWNmY2UyZjc3MTQwMDUxMzAxZjg0NjNmZmIwNDFhMDkwZDlmZDc)
## More Information
* [Website](https://boostnote.io)
* [10hz](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 October!** 🏃💨
* [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
* [Support us via OpenCollective](https://opencollective.com/boostnoteio) : 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.

9
snap/gui/boostnote.desktop Executable file
View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Boostnote
Comment=A note-taking app for programmers
Exec=$SNAP/etc/boostnote/Boostnote
Icon=resources/app.png
MimeType=image/x-foo;
NotShowIn=KDE;

48
snap/snapcraft.yaml Normal file
View File

@@ -0,0 +1,48 @@
name: boostnote
version: '0.1'
summary: A note-taking app for programmers
description: |
Boostnote is an open source note-taking app made for programmers just like you. https://boostnote.io
https://github.com/BoostIO/Boostnote
grade: stable
confinement: strict
apps:
asmstnote:
command: desktop-launch $SNAP/etc/boostnote/Boostnote
plugs:
- browser-support
- network
- unity7
- gsettings
parts:
src:
plugin: nodejs
source: .
deps:
plugin: nil
stage-packages:
- libgconf-2-4
- libnss3
- libxss1
- fontconfig-config
desktop-integration:
plugin: nil
stage-packages:
- libappindicator1
- libdbusmenu-glib4
- libnotify4
- libunity9
launcher:
plugin: dump
source: .
stage:
- etc/boostnote
organize:
dist/Boostnote-linux-x64: etc/boostnote
after: [desktop-glib-only]

View File

@@ -0,0 +1,48 @@
const test = require('ava')
const reorderFolder = require('browser/main/lib/dataApi/reorderFolder')
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 _ = require('lodash')
const TestDummy = require('../fixtures/TestDummy')
const sander = require('sander')
const os = require('os')
const CSON = require('@rokt33r/season')
const storagePath = path.join(os.tmpdir(), 'test/reorder-folder')
test.beforeEach((t) => {
t.context.storage = TestDummy.dummyStorage(storagePath)
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
})
test.serial('Reorder a folder', (t) => {
const storageKey = t.context.storage.cache.key
const firstFolderKey = t.context.storage.json.folders[0].key
const secondFolderKey = t.context.storage.json.folders[1].key
return Promise.resolve()
.then(function doTest () {
return reorderFolder(storageKey, 0, 1)
})
.then(function assert (data) {
t.true(_.nth(data.storage.folders, 0).key === secondFolderKey)
t.true(_.nth(data.storage.folders, 1).key === firstFolderKey)
let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
console.log(path.join(data.storage.path, 'boostnote.json'))
t.true(_.nth(jsonData.folders, 0).key === secondFolderKey)
t.true(_.nth(jsonData.folders, 1).key === firstFolderKey)
})
})
test.after(function after () {
localStorage.clear()
sander.rimrafSync(storagePath)
})

View File

@@ -6,26 +6,30 @@ import _ from 'lodash'
const pickContents = (notes) => notes.map((note) => { return note.content })
let notes = []
let note1, note2
let note1, note2, note3
test.before(t => {
const data1 = { type: 'MARKDOWN_NOTE', content: 'content1', tags: ['tag1'] }
const data2 = { type: 'MARKDOWN_NOTE', content: 'content1\ncontent2', tags: ['tag1', 'tag2'] }
const data3 = { type: 'MARKDOWN_NOTE', content: '#content4', tags: ['tag1'] }
note1 = dummyNote(data1)
note2 = dummyNote(data2)
note3 = dummyNote(data3)
notes = [note1, note2]
notes = [note1, note2, note3]
})
test('it can find notes by tags or words', t => {
// [input, expected content (Array)]
const testCases = [
['#tag1', [note1.content, note2.content]],
['#tag1', [note1.content, note2.content, note3.content]],
['#tag1 #tag2', [note2.content]],
['#tag1 #tag2 #tag3', []],
['content1', [note1.content, note2.content]],
['content1 content2', [note2.content]],
['content1 content2 content3', []]
['content1 content2 content3', []],
['#content4', [note3.content]]
]
testCases.forEach((testCase) => {

View File

@@ -39,6 +39,7 @@ var config = {
'fs-jetpack',
'@rokt33r/markdown-it-math',
'markdown-it-checkbox',
'markdown-it-kbd',
'devtron',
'mixpanel',
'@rokt33r/season',

559
yarn.lock

File diff suppressed because it is too large Load Diff