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

Compare commits

...

173 Commits

Author SHA1 Message Date
Junyoung Choi
ab3ad0eb97 v0.8.20 2018-01-13 19:01:53 +09:00
Junyoung Choi (Sai)
2393889028 Merge pull request #1394 from BoostIO/fix-export-folder-test
Fix exportFolder error
2018-01-13 18:58:45 +09:00
Junyoung Choi
c36ecb1ed1 Fix exportFolder error
writeFileSync doesn't require any errors
2018-01-13 18:48:34 +09:00
Junyoung Choi (Sai)
3e9b28ff0c Merge pull request #1384 from BoostIO/fix-background-color-bug
fix bug happen on solarized-dark CreateFolderModal.
2018-01-13 18:12:59 +09:00
Junyoung Choi (Sai)
d4eec461a9 Merge pull request #1393 from BoostIO/fix-update
Fix windows update
2018-01-13 18:00:44 +09:00
Junyoung Choi (Sai)
b584f37087 Merge pull request #1392 from BoostIO/cm-close-brackets
Cm close brackets
2018-01-13 18:00:12 +09:00
Junyoung Choi
5c75644db2 Check upate every day rather than every hour 2018-01-13 17:36:33 +09:00
Junyoung Choi
72d9e3e00b Fix update error
This error was caused by using super old version of
electron-winstaller.
2018-01-13 17:35:23 +09:00
Sosuke Suzuki
b3d3362f34 set autoCloseBrackets to cm defaultConfigurations 2018-01-13 15:37:14 +09:00
Sosuke Suzuki
1cbaf55cee import the addon for autoCloseBrackets 2018-01-13 15:10:18 +09:00
Sosuke Suzuki
7771875d57 Change CreateFolderInput style from raw color code to variable 2018-01-13 11:37:47 +09:00
Kazz Yokomizo
85937d8e23 Merge pull request #1324 from mslourens/confirmation-dialog
show delete confirmation dialog
2018-01-12 09:37:05 +09:00
Sosuke Suzuki
1480986a3a change submit button style 2018-01-11 18:34:00 +09:00
Sosuke Suzuki
bc968736df add colors for SolarizedDark 2018-01-11 18:30:57 +09:00
Kazz Yokomizo
ad80b8e8b6 Merge pull request #1379 from BoostIO/destroy-initmodal
remove initmodal
2018-01-10 23:36:35 +09:00
Sosuke Suzuki
d44d220c55 change default storage name from debugging to production 2018-01-10 19:40:04 +09:00
Sosuke Suzuki
f6bcef0789 remove unnecessary variables 2018-01-10 19:36:45 +09:00
Sosuke Suzuki
a28ec752e8 remove InitModalComponent 2018-01-10 19:36:13 +09:00
Sosuke Suzuki
48ea5746d9 move init function to Main.js 2018-01-10 19:33:58 +09:00
Kazz Yokomizo
f473d31970 Merge pull request #1368 from marcusstenbeck/patch-1
fix(code-editor): use correct prop for font family
2018-01-05 19:06:57 +09:00
Marcus Stenbeck
9cd1d4b466 fix(code-editor): use correct prop for font family 2018-01-05 10:54:48 +01:00
Kazz Yokomizo
4f02065eaf Merge pull request #1354 from trinode/feature-elixir-support
Elixir syntax highlighting
2018-01-04 20:31:45 +09:00
Kazz Yokomizo
4b85e3e8fb Merge pull request #1363 from BoostIO/fix-note-disppaer-bug
fix bug when add tag, disappear note.
2018-01-04 19:57:40 +09:00
Sosuke Suzuki
e4e8c2205e splid update functions 2018-01-04 18:12:27 +09:00
Maurits Lourens
18649dd074 fixed lint errors 2018-01-04 08:32:42 +01:00
Maurits Lourens
9f9463f0e8 fixed review comments 2018-01-03 23:08:42 +01:00
Kazz Yokomizo
6cf9bc5de2 Merge pull request #1361 from BoostIO/fix-ci-errror
Fix CI error at #1147
2018-01-04 04:07:49 +09:00
Kazu Yokomizo
297b4346c5 Fix CI error at #1147 2018-01-04 03:51:49 +09:00
Kazz Yokomizo
767a203439 Merge pull request #1147 from mslourens/export-folder
export folder as md or text
2018-01-04 03:50:24 +09:00
Kazz Yokomizo
c564c253b1 Merge pull request #1302 from mslourens/open-finder
fixed opening finder on Windows and Linux
2018-01-04 03:39:14 +09:00
Anthony Graham
b4e138e21b Elixir Syntax Highlighting 2018-01-01 21:17:29 +00:00
Kazz Yokomizo
8ca01921c4 Merge pull request #1349 from BoostIO/fix-live-preview-indent-bug
fix bug that config of editorIndentSize is not working.
2017-12-30 16:38:58 +09:00
Sosuke Suzuki
c8b97ffde3 pass fontSize and indentSize to CodeEditor as props 2017-12-30 11:04:13 +09:00
Kazz Yokomizo
abc84e5710 Merge pull request #1347 from BoostIO/fix-solarized-dark-infopanel
fix style
2017-12-29 21:56:55 +09:00
Sosuke Suzuki
d732d195f3 fix style 2017-12-29 21:38:40 +09:00
Kazz Yokomizo
789975abb0 Merge pull request #1343 from BoostIO/fix-table-backgroud-color
add table style in solarized-dark-theme
2017-12-28 22:57:39 +09:00
Sosuke Suzuki
ed1eab7fcc add table style in solarized-dark-theme 2017-12-28 22:48:59 +09:00
Kazz Yokomizo
29b31c114a Merge pull request #1337 from BoostIO/update-readme
Update readme
2017-12-28 11:13:48 +09:00
Kazz Yokomizo
c8cf353c21 Merge pull request #1220 from PaulRosset/add-notification-onChangeUi
Add notification on change ui
2017-12-28 10:45:21 +09:00
Kazz Yokomizo
e82e2c71f1 Update readme 2017-12-28 10:44:07 +09:00
Kazz Yokomizo
dd729c406f Merge pull request #1256 from mslourens/export-html
first attempt to export html
2017-12-28 10:38:55 +09:00
Kazz Yokomizo
3127e85900 Merge pull request #1329 from robbawebba/fix/jump-notes-by-link
Fix linking to other notes
2017-12-26 11:51:51 +09:00
Kazz Yokomizo
304eeb3158 Merge pull request #1331 from ncaron/master
Fix starred item count
2017-12-26 11:41:28 +09:00
Niko Caron
bf781c6b50 Fix starred item count
* Deleting a starred item will now update the starred count in the side nav. (delete from starred set)
* Restoring a starred item will add it the the starred set again.

Fix: #1326
2017-12-23 18:17:48 -04:00
Rob Weber
4f7026969f Fix linking to other notes 2017-12-23 01:33:03 -08:00
Kazz Yokomizo
16d264ebfa Merge pull request #1328 from BoostIO/fix-style
Fix style
2017-12-23 15:32:02 +09:00
Kazu Yokomizo
04ffbe945b Delete unnecessary style 2017-12-23 15:25:45 +09:00
Kazu Yokomizo
974a1a1e7d Fix style 2017-12-23 15:18:16 +09:00
Kazz Yokomizo
ca2c07244f Merge pull request #1321 from mslourens/tooltips
added tooltips like the new note button
2017-12-23 15:12:17 +09:00
Kohei TAKATA
f90786d1c0 Merge pull request #1327 from BoostIO/feature-v0-8-19
v0.8.19
2017-12-23 12:51:13 +09:00
Kohei TAKATA
bdf55568c7 v0.8.19 2017-12-23 12:03:28 +09:00
Maurits Lourens
e262d2f19b fixed lint error 2017-12-21 19:15:34 +01:00
Maurits Lourens
aabfe820ac refactored to prevent duplicate code 2017-12-21 17:41:08 +01:00
Maurits Lourens
3bba5442bd show delete confirmation dialog 2017-12-21 15:57:27 +01:00
Maurits Lourens
6ce1922fb3 added tooltips like the new note button (and consequently extracted some buttons and styles) 2017-12-21 15:23:13 +01:00
Maurits Lourens
9367a404ef converted line-endings back to lf 2017-12-21 09:37:17 +01:00
Kazz Yokomizo
7c8e19c681 Merge pull request #1312 from BoostIO/fix-layout
Fix switch button layout
2017-12-20 18:56:31 +09:00
Kazu Yokomizo
7ccc5eb9b8 Fix switch button layout 2017-12-20 18:50:53 +09:00
Kazz Yokomizo
b4b6d3d07c Merge pull request #1243 from BoostIO/detect-AMA-errors
Detect ama errors
2017-12-20 18:27:24 +09:00
Kazz Yokomizo
9007bac7b2 Merge pull request #1307 from BoostIO/split-markdown
Split markdown
2017-12-20 18:20:49 +09:00
Sosuke Suzuki
df13ca3c92 make splitMode Default 2017-12-20 18:11:01 +09:00
Kazz Yokomizo
d86935acaa Merge pull request #1308 from ytk141/split-icon
Split icon
2017-12-19 13:57:49 +09:00
Yutaka Ishii
72b450d526 icon updated 2017-12-19 10:21:01 +09:00
Sosuke Suzuki
4b7afeeb4f remove unnecesarry state 2017-12-19 03:46:20 +09:00
Sosuke Suzuki
0e0e779cbe remove unnecessary arg 2017-12-18 21:38:58 +09:00
Sosuke Suzuki
89b2f48a06 remove an unnecessary valiable 2017-12-18 19:31:43 +09:00
Sosuke Suzuki
c80bdb8d0c apply ignorePreviewPointerEvents 2017-12-18 19:28:42 +09:00
Sosuke Suzuki
50d89a8ec9 fix to apply fontSize and fontFamily 2017-12-18 19:21:52 +09:00
Sosuke Suzuki
f5ccaa7b48 fix word-wrap 2017-12-18 18:52:59 +09:00
Sosuke Suzuki
e682ee8541 avoid handling events for not split editor 2017-12-18 18:52:33 +09:00
Sosuke Suzuki
caaa7a9e74 implement checkbox 2017-12-18 18:42:35 +09:00
Sosuke Suzuki
6ef0e325e2 fix style 2017-12-18 18:39:40 +09:00
Sosuke Suzuki
ea064deeb8 implement splitEditor 2017-12-18 18:26:25 +09:00
Sosuke Suzuki
8e81609a39 implement minimun splitEditor 2017-12-18 17:40:06 +09:00
Sosuke Suzuki
977e80c829 apply switching style 2017-12-17 02:07:07 +09:00
Sosuke Suzuki
8ba0d10f40 set editorType into Config and state 2017-12-17 02:02:19 +09:00
Sosuke Suzuki
2581091652 add editorType into ConfigManager 2017-12-16 23:17:45 +09:00
Kazz Yokomizo
e72a7ceaea Merge pull request #1207 from ytk141/add-note-mode-tab
add note mode tab
2017-12-16 17:33:49 +09:00
Sosuke Suzuki
a17ddf6d54 use getSendEventCond func 2017-12-16 15:30:21 +09:00
Sosuke Suzuki
b5e2d21f33 split to function send event conditions 2017-12-16 15:30:21 +09:00
Sosuke Suzuki
d09f8dff18 detect internet connection when send events 2017-12-16 15:30:21 +09:00
Sosuke Suzuki
bdb3406dcb modify: change the file where detect Internet disconnection 2017-12-16 15:30:21 +09:00
Sosuke Suzuki
f54b49db1a detect internet disconnection 2017-12-16 15:30:21 +09:00
Kazz Yokomizo
0cc9f006c5 Merge pull request #1217 from SCdF/use-file-metadata-on-import
Use existing file metadata for created and modified dates
2017-12-16 14:29:19 +09:00
Kazz Yokomizo
db1398b65f Merge pull request #1305 from BoostIO/fix-ui-bug
Fix several UI bugs
2017-12-16 13:58:00 +09:00
Kazu Yokomizo
e8192e6c3f Fix several UI bugs 2017-12-16 13:49:53 +09:00
Maurits Lourens
775200bdd6 fixed opening finder on Windows and Linux
fixes #1291 - tested on Ubuntu Linux Mate and Windows 10
2017-12-15 12:57:18 +01:00
Kazz Yokomizo
820a2a093c Merge pull request #1275 from BoostIO/add-pin-note-item-simple
Add Pin to NoteItemSimple
2017-12-15 15:32:26 +09:00
Kazz Yokomizo
d3995b9b10 Merge pull request #1293 from ytk141/Solarized-Dark-Theme
Add Solarized Dark theme
2017-12-15 15:27:43 +09:00
Yutaka Ishii
f6867f9338 Finder style updated 2017-12-15 14:52:58 +09:00
Yutaka Ishii
3e2548fcd5 add active notelist color 2017-12-15 11:04:09 +09:00
Stefan du Fresne
745d250787 Reorder Object.assign
- Respects the dates that may be in input over default dates
 - Respects key and storage over what might be in input
2017-12-14 13:16:37 +00:00
Stefan du Fresne
b1063eb38f Not used to this no semi colon thing 2017-12-14 13:13:29 +00:00
Stefan du Fresne
9032a1debb Use existing file metadata for created and modified dates
NB: this definintely works on OSX. Other operating systems may have
slightly different interpretations of birthtime.

See: https://nodejs.org/api/fs.html#fs_class_fs_stats
2017-12-14 13:13:29 +00:00
Paul Rosset
795fe8ae1d Add isEqual and changing haveToSaveNotif method 2017-12-14 12:26:05 +00:00
Kazz Yokomizo
e5a908af68 Merge pull request #1295 from BoostIO/update-readme
Update readme
2017-12-14 18:26:38 +09:00
Kohei TAKATA
6ce16c1cc0 Merge pull request #1296 from BoostIO/add-lint-plugin
Add lint plugin
2017-12-14 18:22:35 +09:00
Kazu Yokomizo
6ff2a5ac94 Add lint plugin 2017-12-14 18:09:49 +09:00
Kazz Yokomizo
fcea16e43a Update readme 2017-12-14 18:07:27 +09:00
Kazz Yokomizo
7b8e42382e Merge pull request #1294 from BoostIO/update-readme
Update readme
2017-12-14 18:03:38 +09:00
Kazz Yokomizo
a372b5ea39 Update readme 2017-12-14 17:51:48 +09:00
Yutaka Ishii
1aafee2a7c Add Solarized Dark theme 2017-12-14 15:46:29 +09:00
Kazz Yokomizo
7afe3d5181 Merge pull request #1287 from nebbers1111/master
Fixed regex to stop [anytingx] being counted as a checkmark
2017-12-14 12:25:34 +09:00
Maurits Lourens
6fba62d062 fixed review comments 2017-12-13 17:20:22 +01:00
Maurits Lourens
5d46adf8fd fixed review comments 2017-12-13 17:11:43 +01:00
Kazz Yokomizo
eda1f11d42 Merge pull request #1267 from hooskers/add-scroll-past-end
Add scroll past end
2017-12-14 00:54:38 +09:00
Ben Coleman
6431a8255d Fixed trailing spaces 2017-12-12 13:59:38 +00:00
Ben Coleman
48fd1d11e2 Fixed regex to stop [anytingx] being counted as a checkmark 2017-12-12 13:34:37 +00:00
Kazz Yokomizo
4c3e62efad Merge pull request #1284 from BoostIO/fix-ci-error
Fix Ci error
2017-12-12 17:29:14 +09:00
Kazu Yokomizo
52a15a5d92 Fix Ci error 2017-12-12 17:19:58 +09:00
Kazz Yokomizo
57f4aa5995 Merge pull request #1268 from ytk141/color-update
Color update
2017-12-12 17:17:44 +09:00
Yutaka Ishii
ab9ab004b7 delete non-use icon 2017-12-12 17:02:09 +09:00
Yutaka Ishii
ac624eb98f Change Edit Lock Icon 2017-12-12 17:01:33 +09:00
Yutaka Ishii
1a4c37820d little bit darker color for new dark theme 2017-12-12 10:26:55 +09:00
Yutaka Ishii
685206950b restore StatusBar 2017-12-12 10:22:31 +09:00
Kazu Yokomizo
eececf8a93 Add Pin to NoteItemSimple 2017-12-12 02:27:44 +09:00
Kazz Yokomizo
9bc3d65554 Merge pull request #1274 from BoostIO/add-german-documents
Add german documents
2017-12-12 02:09:24 +09:00
Kazz Yokomizo
f9b854ce39 Update debug.md 2017-12-12 01:36:37 +09:00
Kazz Yokomizo
1416968fe5 Update debug.md in German 2017-12-12 01:33:46 +09:00
Kazz Yokomizo
efc183c709 Update build.md in German 2017-12-12 01:28:28 +09:00
Kazz Yokomizo
07a2442718 Add debug.md in German 2017-12-12 01:27:23 +09:00
Kazz Yokomizo
f549c50a58 Create German build.md 2017-12-12 01:26:24 +09:00
Kazz Yokomizo
8d6ce1a2f7 Merge pull request #1272 from oisu/cloud-sync-comment
Fix link to Cloud-Syncing
2017-12-12 01:09:25 +09:00
oisu
c5b33e025e Fix link to Cloud-Syncing 2017-12-11 23:45:34 +09:00
Yutaka Ishii
4983605b23 fixed sideNav icons 2017-12-11 22:03:29 +09:00
Yutaka Ishii
9e8d04d806 progressBar padding修正 2017-12-11 21:52:08 +09:00
Kazz Yokomizo
042f935133 Merge pull request #1269 from BoostIO/add-solarized-dark-theme
Add the Solarized Dark Theme
2017-12-11 20:28:22 +09:00
Kazu Yokomizo
ed9d3639e2 Add the Solarized Dark Theme 2017-12-11 19:01:24 +09:00
Yutaka Ishii
728f105830 dark theme update 2017-12-11 15:42:31 +09:00
Yutaka Ishii
6f359fa6a8 color setting 2017-12-11 15:42:31 +09:00
Yutaka Ishii
57a88743bc icon style update. Delete Zoom 2017-12-11 15:42:30 +09:00
Wade Johnson
667f022086 Remove semicolon 2017-12-10 21:13:21 -08:00
Wade Johnson
b742a3a4cd Put this back?? 2017-12-10 17:58:06 -08:00
Wade Johnson
8d5c9742f8 Add ability to scroll pasted last line of editor 2017-12-09 21:14:10 -08:00
Kohei TAKATA
c2a49efe73 Merge pull request #1120 from mslourens/drag-drop-tabs
implemented drag/drop for tabs
2017-12-09 08:05:57 +09:00
Maurits Lourens
8c8a0ab46d forgot to run lint 2017-12-08 16:21:31 +01:00
Maurits Lourens
959b75bddd export folder as md or text 2017-12-08 16:21:31 +01:00
Kazz Yokomizo
d29d5105f1 Merge pull request #1257 from mslourens/preferences-shortcut
added ctrl+, shortcut to preference modal
2017-12-08 22:15:20 +09:00
Kazz Yokomizo
38e82872a5 Merge pull request #1258 from mslourens/import-in-new-folder
fixed import of new notes
2017-12-08 22:07:38 +09:00
Maurits Lourens
15d9ce1d36 fixed import of new notes 2017-12-08 13:27:16 +01:00
Maurits Lourens
67f7cdb36c added ctrl+, shortcut to preference modal 2017-12-08 12:02:07 +01:00
Maurits Lourens
6a9d4ae0fd first attempt to export html 2017-12-08 11:43:50 +01:00
Kazz Yokomizo
6a761c3fb5 Merge pull request #1254 from BoostIO/fix-folded-sidebar
Fix the folded side bar layout
2017-12-08 14:27:29 +09:00
Kazu Yokomizo
3baf97e69f Fix the folded side bar layout 2017-12-08 14:18:45 +09:00
Kazz Yokomizo
694dc60481 Merge pull request #1244 from mslourens/font-family
fixed incorrect fontFamily for multiple fonts
2017-12-07 17:39:10 +09:00
Kazz Yokomizo
e3c6f0452c Merge pull request #1241 from mslourens/global.styl
fixed global styles
2017-12-06 15:56:47 +09:00
Kazz Yokomizo
ed2401a87b Merge branch 'master' into global.styl 2017-12-06 15:39:46 +09:00
Paul Rosset
cb59458c79 refactor 2017-12-05 18:28:59 +00:00
Paul Rosset
125a493400 Change name for state 2017-12-05 18:24:30 +00:00
Paul Rosset
83910b55d2 Correction eslint code format 2017-12-05 18:18:12 +00:00
Paul Rosset
f4fd131100 Requested Review 2017-12-05 18:16:42 +00:00
Maurits Lourens
cfdc880d8c fixed incorrect fontFamily for multiple fonts 2017-12-05 12:51:16 +01:00
Kazz Yokomizo
7303e8bdd2 Merge pull request #1242 from mslourens/ide-related-gitignore
added IDE related ignore rules
2017-12-05 19:32:05 +09:00
Maurits Lourens
ecde465d9f undo ide related gitignore changes 2017-12-05 11:03:30 +01:00
Maurits Lourens
5c5e70a805 added IDE related ignore rules 2017-12-05 11:02:15 +01:00
Maurits Lourens
4e41d9be55 fixed global styles 2017-12-05 09:06:00 +01:00
Maurits Lourens
d06d94449c forgot to reload tab at oldindex 2017-12-04 19:24:50 +01:00
Maurits Lourens
1af2c83c63 removed the onDragEnd handler 2017-12-04 19:24:50 +01:00
Maurits Lourens
6c75136777 implemented drag/drop for tabs 2017-12-04 19:24:50 +01:00
Kazz Yokomizo
31351e34e1 Merge pull request #1236 from Alaev/patch-1
Added border radius & background color to NavToggleButton
2017-12-04 22:32:08 +09:00
Michael Alaev
a058a774e9 Added border radius with background color
At the moment when you hover the left menu icon its hard to see that you fully hovering it, yes there is a white color and a cursor icon I was thinking it would be useful to have a more visual effect
2017-12-04 15:10:36 +02:00
Kazz Yokomizo
e6db28485c Merge pull request #1194 from fabien0102/checked-style
Add a specific style for checked inputs
2017-12-04 13:48:18 +09:00
Kazz Yokomizo
391bb096d6 Merge pull request #1221 from Paalon/master
Add custom LaTeX delimiters to preferences
2017-12-04 13:45:49 +09:00
Paalon
2b496dc2e5 Get back into original yarn.lock 2017-12-02 17:42:11 +09:00
Paalon
a6e0b30576 Bug fix: fix mistaken name. 2017-12-02 17:15:50 +09:00
paalon
1ac31264b7 Change 'var' to 'const'. 2017-12-02 12:55:10 +09:00
paalon
ca4b8224fd Add LaTeX delimiters preferences 2017-12-02 07:23:12 +09:00
Paul Rosset
d1e5781c24 Correction UiTab 2017-12-01 19:03:04 +00:00
Paul Rosset
c86e451198 Merge branch 'master' of github.com:BoostIO/Boostnote into add-notification-onChangeUi 2017-12-01 17:34:16 +00:00
Paul Rosset
b4a7b547f0 Add notification when not saved 2017-12-01 15:23:23 +00:00
Yutaka Ishii
07b395c24a add note mode tab 2017-11-30 18:36:41 +09:00
fabien0102
53b9630fa5 Remove italic style 2017-11-28 15:18:22 +01:00
fabien0102
f820c3089e Add a specific style for checked inputs 2017-11-27 17:30:16 +01:00
124 changed files with 2643 additions and 992 deletions

2
.gitignore vendored
View File

@@ -8,3 +8,5 @@ node_modules/*
/compiled /compiled
/secret /secret
*.log *.log
.idea
.vscode

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types'
import React from 'react' import React from 'react'
import _ from 'lodash' import _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import path from 'path' import path from 'path'
import copyImage from 'browser/main/lib/dataApi/copyImage' import copyImage from 'browser/main/lib/dataApi/copyImage'
import { findStorage } from 'browser/lib/findStorage' import { findStorage } from 'browser/lib/findStorage'
@@ -59,8 +60,10 @@ export default class CodeEditor extends React.Component {
tabSize: this.props.indentSize, tabSize: this.props.indentSize,
indentWithTabs: this.props.indentType !== 'space', indentWithTabs: this.props.indentType !== 'space',
keyMap: this.props.keyMap, keyMap: this.props.keyMap,
scrollPastEnd: this.props.scrollPastEnd,
inputStyle: 'textarea', inputStyle: 'textarea',
dragDrop: false, dragDrop: false,
autoCloseBrackets: true,
extraKeys: { extraKeys: {
Tab: function (cm) { Tab: function (cm) {
const cursor = cm.getCursor() const cursor = cm.getCursor()
@@ -153,6 +156,10 @@ export default class CodeEditor extends React.Component {
this.editor.setOption('indentWithTabs', this.props.indentType !== 'space') this.editor.setOption('indentWithTabs', this.props.indentType !== 'space')
} }
if (prevProps.scrollPastEnd !== this.props.scrollPastEnd) {
this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd)
}
if (needRefresh) { if (needRefresh) {
this.editor.refresh() this.editor.refresh()
} }
@@ -244,7 +251,7 @@ export default class CodeEditor extends React.Component {
render () { render () {
const { className, fontSize } = this.props const { className, fontSize } = this.props
let fontFamily = this.props.className let fontFamily = this.props.fontFamily
fontFamily = _.isString(fontFamily) && fontFamily.length > 0 fontFamily = _.isString(fontFamily) && fontFamily.length > 0
? [fontFamily].concat(defaultEditorFontFamily) ? [fontFamily].concat(defaultEditorFontFamily)
: defaultEditorFontFamily : defaultEditorFontFamily

View File

@@ -242,6 +242,7 @@ class MarkdownEditor extends React.Component {
fontSize={editorFontSize} fontSize={editorFontSize}
indentType={config.editor.indentType} indentType={config.editor.indentType}
indentSize={editorIndentSize} indentSize={editorIndentSize}
scrollPastEnd={config.editor.scrollPastEnd}
storageKey={storageKey} storageKey={storageKey}
onChange={(e) => this.handleChange(e)} onChange={(e) => this.handleChange(e)}
onBlur={(e) => this.handleBlur(e)} onBlur={(e) => this.handleBlur(e)}
@@ -259,6 +260,7 @@ class MarkdownEditor extends React.Component {
codeBlockFontFamily={config.editor.fontFamily} codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber} lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize} indentSize={editorIndentSize}
scrollPastEnd={config.editor.scrollPastEnd}
ref='preview' ref='preview'
onContextMenu={(e) => this.handleContextMenu(e)} onContextMenu={(e) => this.handleContextMenu(e)}
tabIndex='0' tabIndex='0'

View File

@@ -3,6 +3,7 @@ import React from 'react'
import markdown from 'browser/lib/markdown' import markdown from 'browser/lib/markdown'
import _ from 'lodash' import _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import consts from 'browser/lib/consts' import consts from 'browser/lib/consts'
import Raphael from 'raphael' import Raphael from 'raphael'
import flowchart from 'flowchart' import flowchart from 'flowchart'
@@ -49,12 +50,12 @@ body {
font-size: ${fontSize}px; font-size: ${fontSize}px;
} }
code { code {
font-family: ${codeBlockFontFamily.join(', ')}; font-family: '${codeBlockFontFamily.join("','")}';
background-color: rgba(0,0,0,0.04); background-color: rgba(0,0,0,0.04);
} }
.lineNumber { .lineNumber {
${lineNumber && 'display: block !important;'} ${lineNumber && 'display: block !important;'}
font-family: ${codeBlockFontFamily.join(', ')}; font-family: '${codeBlockFontFamily.join("','")}';
} }
.clipboardButton { .clipboardButton {
@@ -118,6 +119,7 @@ export default class MarkdownPreview extends React.Component {
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e) this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
this.saveAsTextHandler = () => this.handleSaveAsText() this.saveAsTextHandler = () => this.handleSaveAsText()
this.saveAsMdHandler = () => this.handleSaveAsMd() this.saveAsMdHandler = () => this.handleSaveAsMd()
this.saveAsHtmlHandler = () => this.handleSaveAsHtml()
this.printHandler = () => this.handlePrint() this.printHandler = () => this.handlePrint()
this.linkClickHandler = this.handlelinkClick.bind(this) this.linkClickHandler = this.handlelinkClick.bind(this)
@@ -144,10 +146,12 @@ export default class MarkdownPreview extends React.Component {
} }
handleContextMenu (e) { handleContextMenu (e) {
if (!this.props.onContextMenu) return
this.props.onContextMenu(e) this.props.onContextMenu(e)
} }
handleMouseDown (e) { handleMouseDown (e) {
if (!this.props.onMouseDown) return
if (e.target != null) { if (e.target != null) {
switch (e.target.tagName) { switch (e.target.tagName) {
case 'A': case 'A':
@@ -159,6 +163,7 @@ export default class MarkdownPreview extends React.Component {
} }
handleMouseUp (e) { handleMouseUp (e) {
if (!this.props.onMouseUp) return
if (e.target != null && e.target.tagName === 'A') { if (e.target != null && e.target.tagName === 'A') {
return null return null
} }
@@ -173,21 +178,29 @@ export default class MarkdownPreview extends React.Component {
this.exportAsDocument('md') this.exportAsDocument('md')
} }
handleSaveAsHtml () {
this.exportAsDocument('html', (value) => {
return this.refs.root.contentWindow.document.documentElement.outerHTML
})
}
handlePrint () { handlePrint () {
this.refs.root.contentWindow.print() this.refs.root.contentWindow.print()
} }
exportAsDocument (fileType) { exportAsDocument (fileType, formatter) {
const options = { const options = {
filters: [ filters: [
{ name: 'Documents', extensions: [fileType] } { name: 'Documents', extensions: [fileType] }
], ],
properties: ['openFile', 'createDirectory'] properties: ['openFile', 'createDirectory']
} }
const value = formatter ? formatter.call(this, this.props.value) : this.props.value
dialog.showSaveDialog(remote.getCurrentWindow(), options, dialog.showSaveDialog(remote.getCurrentWindow(), options,
(filename) => { (filename) => {
if (filename) { if (filename) {
fs.writeFile(filename, this.props.value, (err) => { fs.writeFile(filename, value, (err) => {
if (err) throw err if (err) throw err
}) })
} }
@@ -223,6 +236,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler)
eventEmitter.on('export:save-text', this.saveAsTextHandler) eventEmitter.on('export:save-text', this.saveAsTextHandler)
eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-md', this.saveAsMdHandler)
eventEmitter.on('export:save-html', this.saveAsHtmlHandler)
eventEmitter.on('print', this.printHandler) eventEmitter.on('print', this.printHandler)
} }
@@ -234,6 +248,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler)
eventEmitter.off('export:save-text', this.saveAsTextHandler) eventEmitter.off('export:save-text', this.saveAsTextHandler)
eventEmitter.off('export:save-md', this.saveAsMdHandler) eventEmitter.off('export:save-md', this.saveAsMdHandler)
eventEmitter.off('export:save-html', this.saveAsHtmlHandler)
eventEmitter.off('print', this.printHandler) eventEmitter.off('print', this.printHandler)
} }
@@ -255,10 +270,10 @@ export default class MarkdownPreview extends React.Component {
const { fontSize, lineNumber, codeBlockTheme } = this.props const { fontSize, lineNumber, codeBlockTheme } = this.props
let { fontFamily, codeBlockFontFamily } = this.props let { fontFamily, codeBlockFontFamily } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0 fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? [fontFamily].concat(defaultFontFamily) ? fontFamily.split(',').map(fontName => fontName.trim()).concat(defaultFontFamily)
: defaultFontFamily : defaultFontFamily
codeBlockFontFamily = _.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0 codeBlockFontFamily = _.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0
? [codeBlockFontFamily].concat(defaultCodeBlockFontFamily) ? codeBlockFontFamily.split(',').map(fontName => fontName.trim()).concat(defaultCodeBlockFontFamily)
: defaultCodeBlockFontFamily : defaultCodeBlockFontFamily
this.setCodeTheme(codeBlockTheme) this.setCodeTheme(codeBlockTheme)

View File

@@ -0,0 +1,93 @@
import React from 'react'
import CodeEditor from 'browser/components/CodeEditor'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import { findStorage } from 'browser/lib/findStorage'
import styles from './MarkdownSplitEditor.styl'
import CSSModules from 'browser/lib/CSSModules'
class MarkdownSplitEditor extends React.Component {
constructor (props) {
super(props)
this.value = props.value
this.focus = () => this.refs.code.focus()
this.reload = () => this.refs.code.reload()
}
handleOnChange () {
this.value = this.refs.code.value
this.props.onChange()
}
handleCheckboxClick (e) {
e.preventDefault()
e.stopPropagation()
const idMatch = /checkbox-([0-9]+)/
const checkedMatch = /\[x\]/i
const uncheckedMatch = /\[ \]/
if (idMatch.test(e.target.getAttribute('id'))) {
const lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
const lines = this.refs.code.value
.split('\n')
const targetLine = lines[lineIndex]
if (targetLine.match(checkedMatch)) {
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
}
if (targetLine.match(uncheckedMatch)) {
lines[lineIndex] = targetLine.replace(uncheckedMatch, '[x]')
}
this.refs.code.setValue(lines.join('\n'))
}
}
render () {
const { config, value, storageKey } = this.props
const storage = findStorage(storageKey)
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
const previewStyle = {}
if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none'
return (
<div styleName='root'>
<CodeEditor
styleName='codeEditor'
ref='code'
mode='GitHub Flavored Markdown'
value={value}
theme={config.editor.theme}
keyMap={config.editor.keyMap}
fontFamily={config.editor.fontFamily}
fontSize={editorFontSize}
indentType={config.editor.indentType}
indentSize={editorIndentSize}
scrollPastEnd={config.editor.scrollPastEnd}
storageKey={storageKey}
onChange={this.handleOnChange.bind(this)}
/>
<MarkdownPreview
style={previewStyle}
styleName='preview'
theme={config.ui.theme}
keyMap={config.editor.keyMap}
fontSize={config.preview.fontSize}
fontFamily={config.preview.fontFamily}
codeBlockTheme={config.preview.codeBlockTheme}
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
ref='preview'
tabInde='0'
value={value}
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
/>
</div>
)
}
}
export default CSSModules(MarkdownSplitEditor, styles)

View File

@@ -0,0 +1,9 @@
.root
width 100%
height 100%
font-size 30px
display flex
.codeEditor
width 50%
.preview
width 50%

View File

@@ -9,6 +9,10 @@
width 34px width 34px
line-height 32px line-height 32px
padding 0 padding 0
&:hover
border: 1px solid #1EC38B;
background-color: alpha(#1EC38B, 30%)
border-radius: 50%;
body[data-theme="white"] body[data-theme="white"]
navWhiteButtonColor() navWhiteButtonColor()

View File

@@ -231,3 +231,77 @@ body[data-theme="dark"]
.item-bottom-tagList-empty .item-bottom-tagList-empty
color $ui-inactive-text-color color $ui-inactive-text-color
vertical-align middle vertical-align middle
body[data-theme="solarized-dark"]
.root
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteList-backgroundColor
.item
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteList-backgroundColor
&:hover
transition 0.15s
// background-color alpha($ui-solarized-dark-noteList-backgroundColor, 20%)
color $ui-solarized-dark-text-color
.item-title
.item-title-icon
.item-bottom-time
transition 0.15s
color $ui-solarized-dark-text-color
.item-bottom-tagList-item
transition 0.15s
background-color alpha($ui-solarized-dark-noteList-backgroundColor, 20%)
color $ui-solarized-dark-text-color
&:active
transition 0.15s
background-color $ui-solarized-dark-noteList-backgroundColor
color $ui-solarized-dark-text-color
.item-title
.item-title-icon
.item-bottom-time
transition 0.15s
color $ui-solarized-dark-text-color
.item-bottom-tagList-item
transition 0.15s
background-color alpha($ui-solarized-dark-noteList-backgroundColor, 10%)
color $ui-solarized-dark-text-color
.item-wrapper
border-color alpha($ui-solarized-dark-button--active-backgroundColor, 60%)
.item--active
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-button-backgroundColor
.item-wrapper
border-color transparent
.item-title
.item-title-icon
.item-bottom-time
color $ui-solarized-dark-text-color
.item-bottom-tagList-item
background-color alpha(white, 10%)
color $ui-solarized-dark-text-color
&:hover
// background-color alpha($ui-solarized-dark-button--active-backgroundColor, 60%)
color #c0392b
.item-bottom-tagList-item
background-color alpha(#fff, 20%)
.item-title
color $ui-inactive-text-color
.item-title-icon
color $ui-inactive-text-color
.item-title-empty
color $ui-inactive-text-color
.item-bottom-tagList-item
background-color alpha($ui-dark-button--active-backgroundColor, 40%)
color $ui-inactive-text-color
.item-bottom-tagList-empty
color $ui-inactive-text-color
vertical-align middle

View File

@@ -14,7 +14,7 @@ import styles from './NoteItemSimple.styl'
* @param {Function} handleNoteContextMenu * @param {Function} handleNoteContextMenu
* @param {Function} handleDragStart * @param {Function} handleDragStart
*/ */
const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu, handleDragStart }) => ( const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu, handleDragStart, pathname }) => (
<div styleName={isActive <div styleName={isActive
? 'item-simple--active' ? 'item-simple--active'
: 'item-simple' : 'item-simple'
@@ -30,6 +30,10 @@ const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu
? <i styleName='item-simple-title-icon' className='fa fa-fw fa-code' /> ? <i styleName='item-simple-title-icon' className='fa fa-fw fa-code' />
: <i styleName='item-simple-title-icon' className='fa fa-fw fa-file-text-o' /> : <i styleName='item-simple-title-icon' className='fa fa-fw fa-file-text-o' />
} }
{note.isPinned && !pathname.match(/\/home|\/starred|\/trash/)
? <i styleName='item-pin' className='fa fa-thumb-tack' />
: ''
}
{note.title.trim().length > 0 {note.title.trim().length > 0
? note.title ? note.title
: <span styleName='item-simple-title-empty'>Empty</span> : <span styleName='item-simple-title-empty'>Empty</span>

View File

@@ -50,6 +50,7 @@ $control-height = 30px
.item-simple-title .item-simple-title
font-size 13px font-size 13px
height 40px height 40px
padding-right 20px
box-sizing border-box box-sizing border-box
line-height 24px line-height 24px
padding-top 8px padding-top 8px
@@ -67,6 +68,15 @@ $control-height = 30px
font-weight normal font-weight normal
color $ui-inactive-text-color color $ui-inactive-text-color
.item-pin
position absolute
right 0px
top 12px
color #E54D42
font-size 14px
padding 0
border-radius 17px
body[data-theme="white"] body[data-theme="white"]
.item-simple .item-simple
background-color $ui-white-noteList-backgroundColor background-color $ui-white-noteList-backgroundColor
@@ -143,3 +153,57 @@ body[data-theme="dark"]
.item-simple-title-empty .item-simple-title-empty
color $ui-dark-inactive-text-color color $ui-dark-inactive-text-color
body[data-theme="solarized-dark"]
.root
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteList-backgroundColor
.item-simple
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteList-backgroundColor
&:hover
transition 0.15s
// background-color alpha($ui-dark-button--active-backgroundColor, 20%)
color $ui-solarized-dark-text-color
.item-simple-title
.item-simple-title-icon
.item-simple-bottom-time
transition 0.15s
color $ui-solarized-dark-text-color
.item-simple-bottom-tagList-item
transition 0.15s
background-color alpha(#fff, 20%)
color $ui-solarized-dark-text-color
&:active
transition 0.15s
background-color $ui-solarized-dark-button--active-backgroundColor
color $ui-solarized-dark-text-color
.item-simple-title
.item-simple-title-icon
.item-simple-bottom-time
transition 0.15s
color $ui-solarized-dark-text-color
.item-simple-bottom-tagList-item
transition 0.15s
background-color alpha(white, 10%)
color $ui-solarized-dark-text-color
.item-simple--active
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-button--active-backgroundColor
.item-simple-wrapper
border-color transparent
.item-simple-title
.item-simple-title-icon
.item-simple-bottom-time
color $ui-solarized-dark-text-color
.item-simple-bottom-tagList-item
background-color alpha(white, 10%)
color $ui-solarized-dark-text-color
&:hover
// background-color alpha($ui-dark-button--active-backgroundColor, 60%)
color #c0392b
.item-simple-bottom-tagList-item
background-color alpha(#fff, 20%)

View File

@@ -29,3 +29,15 @@ body[data-theme="dark"]
transition 0.2s transition 0.2s
&:hover &:hover
color #5CB85C color #5CB85C
body[data-theme="solarized-dark"]
.notification-area
background-color none
.notification-link
color $ui-solarized-dark-text-color
border none
background-color $ui-solarized-dark-button-backgroundColor
&:hover
color #5CB85C

View File

@@ -41,7 +41,7 @@ const SideNavFilter = ({
<div styleName='iconWrap'> <div styleName='iconWrap'>
<img src={isStarredActive <img src={isStarredActive
? '../resources/icon/icon-star-active.svg' ? '../resources/icon/icon-star-active.svg'
: '../resources/icon/icon-star.svg' : '../resources/icon/icon-star-sidenav.svg'
} }
/> />
</div> </div>
@@ -55,7 +55,7 @@ const SideNavFilter = ({
<div styleName='iconWrap'> <div styleName='iconWrap'>
<img src={isTrashedActive <img src={isTrashedActive
? '../resources/icon/icon-trash-active.svg' ? '../resources/icon/icon-trash-active.svg'
: '../resources/icon/icon-trash.svg' : '../resources/icon/icon-trash-sidenav.svg'
} }
/> />
</div> </div>

View File

@@ -55,7 +55,7 @@
.menu--folded .menu--folded
@extend .menu @extend .menu
.menu-button, .menu-button--active .menu-button, .menu-button--active, .menu-button-star--active, .menu-button-trash--active
text-align center text-align center
padding 0 12px padding 0 12px
&:hover .menu-button-label &:hover .menu-button-label
@@ -182,4 +182,47 @@ body[data-theme="dark"]
background-color alpha($ui-dark-button--active-backgroundColor, 50%) background-color alpha($ui-dark-button--active-backgroundColor, 50%)
color #5D9E36 color #5D9E36
.menu-button-label .menu-button-label
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.menu-button
&:active
background-color $ui-solarized-dark-noteList-backgroundColor
color $ui-solarized-dark-text-color
&:hover
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
.menu-button--active
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
.menu-button-label
color $ui-solarized-dark-text-color
&:hover
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
.menu-button-label
color $ui-solarized-dark-text-color
.menu-button-star--active
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
.menu-button-label
color $ui-solarized-dark-text-color
&:hover
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
.menu-button-label
color $ui-solarized-dark-text-color
.menu-button-trash--active
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
.menu-button-label
color $ui-solarized-dark-text-color
&:hover
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
.menu-button-label
color $ui-solarized-dark-text-color

View File

@@ -85,6 +85,15 @@ class SnippetTab extends React.Component {
}) })
} }
handleDragStart (e) {
e.dataTransfer.dropEffect = 'move'
this.props.onDragStart(e)
}
handleDrop (e) {
this.props.onDrop(e)
}
render () { render () {
const { isActive, snippet, isDeletable } = this.props const { isActive, snippet, isDeletable } = this.props
return ( return (
@@ -98,6 +107,9 @@ class SnippetTab extends React.Component {
onClick={(e) => this.handleClick(e)} onClick={(e) => this.handleClick(e)}
onDoubleClick={(e) => this.handleRenameClick(e)} onDoubleClick={(e) => this.handleRenameClick(e)}
onContextMenu={(e) => this.handleContextMenu(e)} onContextMenu={(e) => this.handleContextMenu(e)}
onDragStart={(e) => this.handleDragStart(e)}
onDrop={(e) => this.handleDrop(e)}
draggable='true'
> >
{snippet.name.trim().length > 0 {snippet.name.trim().length > 0
? snippet.name ? snippet.name
@@ -127,6 +139,7 @@ class SnippetTab extends React.Component {
} }
SnippetTab.propTypes = { SnippetTab.propTypes = {
} }
export default CSSModules(SnippetTab, styles) export default CSSModules(SnippetTab, styles)

View File

@@ -38,7 +38,7 @@
text-align center text-align center
border none border none
padding 0 padding 0
color transparent color $ui-inactive-text-color
background-color transparent background-color transparent
border-radius 2px border-radius 2px
@@ -89,3 +89,50 @@ body[data-theme="dark"]
.input .input
background-color $ui-dark-button--hover-backgroundColor background-color $ui-dark-button--hover-backgroundColor
color $ui-dark-text-color color $ui-dark-text-color
.deleteButton
color alpha($ui-dark-text-color, 30%)
body[data-theme="solarized-dark"]
.root
color $ui-solarized-dark-text-color
border-color $ui-dark-borderColor
&:hover
background-color $ui-solarized-dark-noteDetail-backgroundColor
.deleteButton
color $ui-solarized-dark-text-color
&:hover
background-color darken($ui-solarized-dark-noteDetail-backgroundColor, 15%)
&:active
color $ui-solarized-dark-text-color
background-color $ui-dark-button--active-backgroundColor
.root--active
color $ui-solarized-dark-text-color
border-color $ui-solarized-dark-borderColor
&:hover
background-color $ui-solarized-dark-noteDetail-backgroundColor
.deleteButton
color $ui-solarized-dark-text-color
&:hover
background-color darken($ui-solarized-dark-noteDetail-backgroundColor, 15%)
&:active
color $ui-solarized-dark-text-color
background-color $ui-dark-button--active-backgroundColor
.button
border none
color $ui-solarized-dark-text-color
background-color transparent
transition color background-color 0.15s
border-left 4px solid transparent
&:hover
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-noteDetail-backgroundColor
.input
background-color $ui-solarized-dark-noteDetail-backgroundColor
color $ui-solarized-dark-text-color
.deleteButton
color alpha($ui-solarized-dark-text-color, 30%)

View File

@@ -108,4 +108,23 @@ body[data-theme="dark"]
background-color alpha($ui-dark-button--active-backgroundColor, 50%) background-color alpha($ui-dark-button--active-backgroundColor, 50%)
&:hover &:hover
color $ui-dark-text-color color $ui-dark-text-color
background-color alpha($ui-dark-button--active-backgroundColor, 50%) background-color alpha($ui-dark-button--active-backgroundColor, 50%)
body[data-theme="solarized-dark"]
.folderList-item
&:hover
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
&:active
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
.folderList-item--active
@extend .folderList-item
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
&:active
background-color $ui-solarized-dark-button-backgroundColor
&:hover
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor

View File

@@ -16,7 +16,9 @@ const TodoListPercentage = ({
}) => ( }) => (
<div styleName='percentageBar' style={{display: isNaN(percentageOfTodo) ? 'none' : ''}}> <div styleName='percentageBar' style={{display: isNaN(percentageOfTodo) ? 'none' : ''}}>
<div styleName='progressBar' style={{width: `${percentageOfTodo}%`}}> <div styleName='progressBar' style={{width: `${percentageOfTodo}%`}}>
<p styleName='percentageText'>{percentageOfTodo}%</p> <div styleName='progressBarInner'>
<p styleName='percentageText'>{percentageOfTodo}%</p>
</div>
</div> </div>
</div> </div>
) )

View File

@@ -16,17 +16,36 @@
border-radius 2px border-radius 2px
transition 0.4s cubic-bezier(0.4, 0.4, 0, 1) transition 0.4s cubic-bezier(0.4, 0.4, 0, 1)
.progressBarInner
padding 0 10px
min-width 1px
height 100%
display -webkit-box
display box
justify-content center
align-items center
.percentageText .percentageText
color #f4f4f4 color #f4f4f4
padding: 2px 43%
font-weight 600 font-weight 600
body[data-theme="dark"] body[data-theme="dark"]
.percentageBar .percentageBar
background-color #363A3D background-color #444444
.progressBar .progressBar
background-color: alpha(#939395, 50%) background-color: #1EC38B
.percentageText .percentageText
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.percentageBar
background-color #002b36
.progressBar
background-color: #2aa198
.percentageText
color #fdf6e3

View File

@@ -77,6 +77,9 @@ body
li li
label.taskListItem label.taskListItem
margin-left -2em margin-left -2em
&.checked
text-decoration line-through
opacity 0.5
div.math-rendered div.math-rendered
text-align center text-align center
.math-failed .math-failed
@@ -117,6 +120,7 @@ hr
margin 15px 0 margin 15px 0
h1, h2, h3, h4, h5, h6 h1, h2, h3, h4, h5, h6
font-weight bold font-weight bold
word-wrap break-word
h1 h1
font-size 2.55em font-size 2.55em
padding-bottom 0.3em padding-bottom 0.3em
@@ -154,6 +158,7 @@ p
line-height 1.6em line-height 1.6em
margin 0 0 1em margin 0 0 1em
white-space pre-line white-space pre-line
word-wrap break-word
img img
max-width 100% max-width 100%
strong, b strong, b
@@ -329,4 +334,31 @@ body[data-theme="dark"]
border-right solid 1px themeDarkTableBorder border-right solid 1px themeDarkTableBorder
kbd kbd
background-color themeDarkBorder background-color themeDarkBorder
color themeDarkText color themeDarkText
themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor
themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%)
themeSolarizedDarkTableHead = themeSolarizedDarkTableEven
themeSolarizedDarkTableBorder = themeDarkBorder
body[data-theme="solarized-dark"]
color $ui-solarized-dark-text-color
border-color themeDarkBorder
background-color $ui-solarized-dark-noteDetail-backgroundColor
table
thead
tr
background-color themeSolarizedDarkTableHead
th
border-color themeSolarizedDarkTableBorder
&:last-child
border-right solid 1px themeSolarizedDarkTableBorder
tbody
tr:nth-child(2n + 1)
background-color themeSolarizedDarkTableOdd
tr:nth-child(2n)
background-color themeSolarizedDarkTableEven
td
border-color themeSolarizedDarkTableBorder
&:last-child
border-right solid 1px themeSolarizedDarkTableBorder

View File

@@ -116,3 +116,41 @@ body[data-theme="dark"]
absolute top bottom right absolute top bottom right
left $nav-width + $list-width left $nav-width + $list-width
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-backgroundColor
.search
border-color $ui-solarized-dark-borderColor
.search-input
color $ui-dark-text-color
.result
background-color $ui-solarized-dark-backgroundColor
.result-nav
background-color $ui-solarized-dark-backgroundColor
label
color $ui-dark-text-color
.result-nav-menu
navDarkButtonColor()
.result-nav-menu--active
background-color $ui-solarized-dark-button-backgroundColor
color $ui-dark-button--active-color
&:hover
background-color $ui-dark-button--active-backgroundColor
.result-list
border-color $ui-solarized-dark-borderColor
box-shadow none
top 0
.result-detail
absolute top bottom right
left $nav-width + $list-width
background-color $ui-solarized-dark-backgroundColor

View File

@@ -5,6 +5,7 @@ import MarkdownPreview from 'browser/components/MarkdownPreview'
import MarkdownEditor from 'browser/components/MarkdownEditor' import MarkdownEditor from 'browser/components/MarkdownEditor'
import CodeEditor from 'browser/components/CodeEditor' import CodeEditor from 'browser/components/CodeEditor'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import { findStorage } from 'browser/lib/findStorage' import { findStorage } from 'browser/lib/findStorage'
const electron = require('electron') const electron = require('electron')
@@ -157,6 +158,7 @@ class NoteDetail extends React.Component {
indentType={config.editor.indentType} indentType={config.editor.indentType}
indentSize={editorIndentSize} indentSize={editorIndentSize}
keyMap={config.editor.keyMap} keyMap={config.editor.keyMap}
scrollPastEnd={config.editor.scrollPastEnd}
readOnly readOnly
ref={'code-' + index} ref={'code-' + index}
/> />

View File

@@ -95,3 +95,35 @@ body[data-theme="dark"]
&:hover &:hover
color white color white
background-color $ui-dark-button--hover-backgroundColor background-color $ui-dark-button--hover-backgroundColor
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-backgroundColor
.description
border-color $ui-dark-borderColor
background-color $ui-solarized-dark-backgroundColor
.description-textarea
background-color $ui-solarized-dark-backgroundColor
color white
.tabList
background-color $ui-solarized-dark-backgroundColor
.tabList-item
border-color $ui-dark-borderColor
&:hover
background-color $ui-dark-button--hover-backgroundColor
.tabList-item-button
border none
color $ui-dark-text-color
background-color transparent
transition color background-color 0.15s
border-left 4px solid transparent
&:hover
color white
background-color $ui-dark-button--hover-backgroundColor

View File

@@ -86,6 +86,8 @@ nodeIpc.connectTo(
document.body.setAttribute('data-theme', 'dark') document.body.setAttribute('data-theme', 'dark')
} else if (config.ui.theme === 'white') { } else if (config.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white') document.body.setAttribute('data-theme', 'white')
} else if (config.ui.theme === 'solarized-dark') {
document.body.setAttribute('data-theme', 'solarized-dark')
} else { } else {
document.body.setAttribute('data-theme', 'default') document.body.setAttribute('data-theme', 'default')
} }

View File

@@ -1,3 +1,5 @@
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
CodeMirror.modeInfo.push({name: 'Stylus', mime: 'text/x-styl', mode: 'stylus', ext: ['styl'], alias: ['styl']}) CodeMirror.modeInfo.push({name: 'Stylus', mime: 'text/x-styl', mode: 'stylus', ext: ['styl'], alias: ['styl']})
CodeMirror.modeInfo.push({name: 'Elixir', mime: 'text/x-elixir', mode: 'elixir', ext: ['ex']})

View File

@@ -5,7 +5,7 @@ export function getTodoStatus (content) {
splitted.forEach((line) => { splitted.forEach((line) => {
const trimmedLine = line.trim() const trimmedLine = line.trim()
if (trimmedLine.match(/^[\+\-\*] \[\s|x\] ./)) { if (trimmedLine.match(/^[\+\-\*] \[(\s|x)\] ./)) {
numberOfTodo++ numberOfTodo++
} }
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) { if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) {

View File

@@ -2,9 +2,11 @@ import markdownit from 'markdown-it'
import emoji from 'markdown-it-emoji' import emoji from 'markdown-it-emoji'
import math from '@rokt33r/markdown-it-math' import math from '@rokt33r/markdown-it-math'
import _ from 'lodash' import _ from 'lodash'
import ConfigManager from 'browser/main/lib/ConfigManager'
// FIXME We should not depend on global variable. // FIXME We should not depend on global variable.
const katex = window.katex const katex = window.katex
const config = ConfigManager.get()
function createGutter (str) { function createGutter (str) {
const lc = (str.match(/\n/g) || []).length const lc = (str.match(/\n/g) || []).length
@@ -39,6 +41,10 @@ md.use(emoji, {
shortcuts: {} shortcuts: {}
}) })
md.use(math, { md.use(math, {
inlineOpen: config.preview.latexInlineOpen,
inlineClose: config.preview.latexInlineClose,
blockOpen: config.preview.latexBlockOpen,
blockClose: config.preview.latexBlockClose,
inlineRenderer: function (str) { inlineRenderer: function (str) {
let output = '' let output = ''
try { try {
@@ -109,7 +115,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
if (state.parentType === 'list') { if (state.parentType === 'list') {
const match = content.match(/^\[( |x)\] ?(.+)/i) const match = content.match(/^\[( |x)\] ?(.+)/i)
if (match) { if (match) {
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>` content = `<label class='taskListItem${match[1] !== ' ' ? ' checked' : ''}' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>`
} }
} }

View File

@@ -22,3 +22,9 @@ body[data-theme="dark"]
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
.empty-message .empty-message
color $ui-dark-inactive-text-color color $ui-dark-inactive-text-color
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-noteDetail-backgroundColor
.empty-message
color $ui-solarized-dark-text-color

View File

@@ -0,0 +1,19 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './FullscreenButton.styl'
const FullscreenButton = ({
onClick
}) => (
<button styleName='control-fullScreenButton' title='Fullscreen' onMouseDown={(e) => onClick(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
<span styleName='tooltip'>Fullscreen</span>
</button>
)
FullscreenButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(FullscreenButton, styles)

View File

@@ -0,0 +1,22 @@
.control-fullScreenButton
top 80px
topBarButtonRight()
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
right 0
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="dark"]
.control-fullScreenButton
topBarButtonDark()

View File

@@ -10,6 +10,7 @@ const InfoButton = ({
onClick={(e) => onClick(e)} onClick={(e) => onClick(e)}
> >
<img className='infoButton' src='../resources/icon/icon-info.svg' /> <img className='infoButton' src='../resources/icon/icon-info.svg' />
<span styleName='tooltip'>Info</span>
</button> </button>
) )

View File

@@ -1,7 +1,21 @@
.control-infoButton .control-infoButton
top 10px top 10px
margin-bottom 10px topBarButtonRight()
topBarButtonLight() &:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
right 0
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.infoButton .infoButton
padding 0px padding 0px

View File

@@ -4,7 +4,7 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'
const InfoPanel = ({ const InfoPanel = ({
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type, print storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, exportAsHtml, wordCount, letterCount, type, print
}) => ( }) => (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}> <div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div> <div>
@@ -57,17 +57,22 @@ const InfoPanel = ({
<div id='export-wrap'> <div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}> <button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o fa-fw' /> <i className='fa fa-file-code-o' />
<p>.md</p> <p>.md</p>
</button> </button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}> <button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o fa-fw' /> <i className='fa fa-file-text-o' />
<p>.txt</p> <p>.txt</p>
</button> </button>
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
<i className='fa fa-html5' />
<p>.html</p>
</button>
<button styleName='export--enable' onClick={(e) => print(e)}> <button styleName='export--enable' onClick={(e) => print(e)}>
<i className='fa fa-print fa-fw' /> <i className='fa fa-print' />
<p>Print</p> <p>Print</p>
</button> </button>
</div> </div>
@@ -82,6 +87,7 @@ InfoPanel.propTypes = {
createdAt: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired,
exportAsMd: PropTypes.func.isRequired, exportAsMd: PropTypes.func.isRequired,
exportAsTxt: PropTypes.func.isRequired, exportAsTxt: PropTypes.func.isRequired,
exportAsHtml: PropTypes.func.isRequired,
wordCount: PropTypes.number, wordCount: PropTypes.number,
letterCount: PropTypes.number, letterCount: PropTypes.number,
type: PropTypes.string.isRequired, type: PropTypes.string.isRequired,

View File

@@ -41,12 +41,12 @@
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1) box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
border-radius 2px border-radius 2px
.count-wrap .count-wrap
display flex display flex
position relative position relative
width 100% width 100%
.count-number .count-number
position relative position relative
display block display block
width 50% width 50%
@@ -81,15 +81,15 @@
margin-bottom 6px margin-bottom 6px
.infoPanel-trash .infoPanel-trash
color #EA4447 color #EA4447
font-weight 600 font-weight 600
font-size 14px font-size 14px
width 70px width 70px
background-color rgba(226,33,113,0.1) background-color rgba(226,33,113,0.1)
border none border none
outline none outline none
border-radius 2px border-radius 2px
margin-right 5px margin-right 5px
padding 2px 5px padding 2px 5px
[id=export-wrap] [id=export-wrap]
@@ -160,4 +160,44 @@ body[data-theme="dark"]
p p
color $ui-dark-inactive-text-color color $ui-dark-inactive-text-color
&:hover &:hover
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.control-infoButton-panel
background-color $ui-solarized-dark-noteList-backgroundColor
.control-infoButton-panel-trash
background-color $ui-solarized-ark-noteList-backgroundColor
.modification-date
color $ui-solarized-ark-text-color
.modification-date-desc
color $ui-inactive-text-color
.infoPanel-defaul-count
color $ui-solarized-dark-text-color
.infoPanel-sub-count
color $ui-inactive-text-color
.infoPanel-default
color $ui-solarized-ark-text-color
.infoPanel-sub
color $ui-inactive-text-color
.infoPanel-noteLink
background-color alpha($ui-solarized-dark-borderColor, 20%)
color $ui-solarized-dark-text-color
[id=export-wrap]
button
color $ui-dark-inactive-text-color
&:hover
background-color alpha($ui-solarized-dark-borderColor, 20%)
color $ui-solarized-ark-text-color
p
color $ui-dark-inactive-text-color
&:hover
color $ui-solarized-ark-text-color

View File

@@ -4,7 +4,7 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'
const InfoPanelTrashed = ({ const InfoPanelTrashed = ({
storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt storageName, folderName, updatedAt, createdAt, exportAsMd, exportAsTxt, exportAsHtml
}) => ( }) => (
<div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}> <div className='infoPanel' styleName='control-infoButton-panel-trash' style={{display: 'none'}}>
<div> <div>
@@ -31,17 +31,22 @@ const InfoPanelTrashed = ({
<div id='export-wrap'> <div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}> <button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o fa-fw' /> <i className='fa fa-file-code-o' />
<p>.md</p> <p>.md</p>
</button> </button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}> <button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o fa-fw' /> <i className='fa fa-file-text-o' />
<p>.txt</p> <p>.txt</p>
</button> </button>
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
<i className='fa fa-html5' />
<p>.html</p>
</button>
<button styleName='export--unable'> <button styleName='export--unable'>
<i className='fa fa-file-pdf-o fa-fw' /> <i className='fa fa-file-pdf-o' />
<p>.pdf</p> <p>.pdf</p>
</button> </button>
</div> </div>
@@ -54,7 +59,8 @@ InfoPanelTrashed.propTypes = {
updatedAt: PropTypes.string.isRequired, updatedAt: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired,
exportAsMd: PropTypes.func.isRequired, exportAsMd: PropTypes.func.isRequired,
exportAsTxt: PropTypes.func.isRequired exportAsTxt: PropTypes.func.isRequired,
exportAsHtml: PropTypes.func.isRequired
} }
export default CSSModules(InfoPanelTrashed, styles) export default CSSModules(InfoPanelTrashed, styles)

View File

@@ -3,6 +3,7 @@ import React from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './MarkdownNoteDetail.styl' import styles from './MarkdownNoteDetail.styl'
import MarkdownEditor from 'browser/components/MarkdownEditor' import MarkdownEditor from 'browser/components/MarkdownEditor'
import MarkdownSplitEditor from 'browser/components/MarkdownSplitEditor'
import TodoListPercentage from 'browser/components/TodoListPercentage' import TodoListPercentage from 'browser/components/TodoListPercentage'
import StarButton from './StarButton' import StarButton from './StarButton'
import TagSelect from './TagSelect' import TagSelect from './TagSelect'
@@ -15,19 +16,18 @@ import StatusBar from '../StatusBar'
import _ from 'lodash' import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import ConfigManager from 'browser/main/lib/ConfigManager'
import TrashButton from './TrashButton' import TrashButton from './TrashButton'
import FullscreenButton from './FullscreenButton'
import PermanentDeleteButton from './PermanentDeleteButton' import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton' import InfoButton from './InfoButton'
import ToggleModeButton from './ToggleModeButton'
import InfoPanel from './InfoPanel' import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed' import InfoPanelTrashed from './InfoPanelTrashed'
import { formatDate } from 'browser/lib/date-formatter' import { formatDate } from 'browser/lib/date-formatter'
import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus' import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus'
import striptags from 'striptags' import striptags from 'striptags'
const electron = require('electron')
const { remote } = electron
const { dialog } = remote
class MarkdownNoteDetail extends React.Component { class MarkdownNoteDetail extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -39,7 +39,8 @@ class MarkdownNoteDetail extends React.Component {
content: '' content: ''
}, props.note), }, props.note),
isLockButtonShown: false, isLockButtonShown: false,
isLocked: false isLocked: false,
editorType: props.config.editor.type
} }
this.dispatchTimer = null this.dispatchTimer = null
@@ -74,17 +75,22 @@ class MarkdownNoteDetail extends React.Component {
ee.off('topbar:togglelockbutton', this.toggleLockButton) ee.off('topbar:togglelockbutton', this.toggleLockButton)
} }
handleChange (e) { handleUpdateTag () {
const { note } = this.state const { note } = this.state
note.content = this.refs.content.value
if (this.refs.tags) note.tags = this.refs.tags.value if (this.refs.tags) note.tags = this.refs.tags.value
note.title = markdown.strip(striptags(findNoteTitle(note.content))) this.updateNote(note)
note.updatedAt = new Date() }
this.setState({ handleUpdateContent () {
note const { note } = this.state
}, () => { note.content = this.refs.content.value
note.title = markdown.strip(striptags(findNoteTitle(note.content)))
this.updateNote(note)
}
updateNote (note) {
note.updatedAt = new Date()
this.setState({note}, () => {
this.save() this.save()
}) })
} }
@@ -170,41 +176,44 @@ class MarkdownNoteDetail extends React.Component {
ee.emit('export:save-text') ee.emit('export:save-text')
} }
exportAsHtml () {
ee.emit('export:save-html')
}
handleTrashButtonClick (e) { handleTrashButtonClick (e) {
const { note } = this.state const { note } = this.state
const { isTrashed } = note const { isTrashed } = note
const { confirmDeletion } = this.props
if (isTrashed) { if (isTrashed) {
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { if (confirmDeletion(true)) {
type: 'warning', const {note, dispatch} = this.props
message: 'Confirm note deletion', dataApi
detail: 'This will permanently remove this note.', .deleteNote(note.storage, note.key)
buttons: ['Confirm', 'Cancel'] .then((data) => {
}) const dispatchHandler = () => {
if (dialogueButtonIndex === 1) return dispatch({
const { note, dispatch } = this.props type: 'DELETE_NOTE',
dataApi storageKey: data.storageKey,
.deleteNote(note.storage, note.key) noteKey: data.noteKey
.then((data) => { })
const dispatchHandler = () => { }
dispatch({ ee.once('list:moved', dispatchHandler)
type: 'DELETE_NOTE', })
storageKey: data.storageKey, }
noteKey: data.noteKey
})
}
ee.once('list:moved', dispatchHandler)
})
} else { } else {
note.isTrashed = true if (confirmDeletion()) {
note.isTrashed = true
this.setState({ this.setState({
note note
}, () => { }, () => {
this.save() this.save()
}) })
ee.emit('list:next')
}
} }
ee.emit('list:next')
} }
handleUndoButtonClick (e) { handleUndoButtonClick (e) {
@@ -233,7 +242,7 @@ class MarkdownNoteDetail extends React.Component {
} }
getToggleLockButton () { getToggleLockButton () {
return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg' return this.state.isLocked ? '../resources/icon/icon-previewoff-on.svg' : '../resources/icon/icon-previewoff-off.svg'
} }
handleDeleteKeyDown (e) { handleDeleteKeyDown (e) {
@@ -262,9 +271,42 @@ class MarkdownNoteDetail extends React.Component {
ee.emit('print') ee.emit('print')
} }
render () { handleSwitchMode (type) {
const { data, config, location } = this.props this.setState({ editorType: type }, () => {
const newConfig = Object.assign({}, this.props.config)
newConfig.editor.type = type
ConfigManager.set(newConfig)
})
}
renderEditor () {
const { config, ignorePreviewPointerEvents } = this.props
const { note } = this.state const { note } = this.state
if (this.state.editorType === 'EDITOR_PREVIEW') {
return <MarkdownEditor
ref='content'
styleName='body-noteEditor'
config={config}
value={note.content}
storageKey={note.storage}
onChange={this.handleUpdateContent.bind(this)}
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
/>
} else {
return <MarkdownSplitEditor
ref='content'
config={config}
value={note.content}
storageKey={note.storage}
onChange={this.handleUpdateContent.bind(this)}
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
/>
}
}
render () {
const { data, location } = this.props
const { note, editorType } = this.state
const storageKey = note.storage const storageKey = note.storage
const folderKey = note.folder const folderKey = note.folder
@@ -296,6 +338,7 @@ class MarkdownNoteDetail extends React.Component {
folderName={currentOption.folder.name} folderName={currentOption.folder.name}
updatedAt={formatDate(note.updatedAt)} updatedAt={formatDate(note.updatedAt)}
createdAt={formatDate(note.createdAt)} createdAt={formatDate(note.createdAt)}
exportAsHtml={this.exportAsHtml}
exportAsMd={this.exportAsMd} exportAsMd={this.exportAsMd}
exportAsTxt={this.exportAsTxt} exportAsTxt={this.exportAsTxt}
/> />
@@ -316,11 +359,12 @@ class MarkdownNoteDetail extends React.Component {
<TagSelect <TagSelect
ref='tags' ref='tags'
value={this.state.note.tags} value={this.state.note.tags}
onChange={(e) => this.handleChange(e)} onChange={this.handleUpdateTag.bind(this)}
/>
<TodoListPercentage
percentageOfTodo={getTodoPercentageOfCompleted(note.content)}
/> />
<ToggleModeButton onClick={(e) => this.handleSwitchMode(e)} editorType={editorType} />
<TodoListPercentage percentageOfTodo={getTodoPercentageOfCompleted(note.content)} />
</div> </div>
<div styleName='info-right'> <div styleName='info-right'>
<InfoButton <InfoButton
@@ -347,11 +391,7 @@ class MarkdownNoteDetail extends React.Component {
) )
})()} })()}
<button styleName='control-fullScreenButton' <FullscreenButton onClick={(e) => this.handleFullScreenButton(e)} />
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
</button>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} /> <TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
@@ -363,6 +403,7 @@ class MarkdownNoteDetail extends React.Component {
createdAt={formatDate(note.createdAt)} createdAt={formatDate(note.createdAt)}
exportAsMd={this.exportAsMd} exportAsMd={this.exportAsMd}
exportAsTxt={this.exportAsTxt} exportAsTxt={this.exportAsTxt}
exportAsHtml={this.exportAsHtml}
wordCount={note.content.split(' ').length} wordCount={note.content.split(' ').length}
letterCount={note.content.replace(/\r?\n/g, '').length} letterCount={note.content.replace(/\r?\n/g, '').length}
type={note.type} type={note.type}
@@ -380,15 +421,7 @@ class MarkdownNoteDetail extends React.Component {
{location.pathname === '/trashed' ? trashTopBar : detailTopBar} {location.pathname === '/trashed' ? trashTopBar : detailTopBar}
<div styleName='body'> <div styleName='body'>
<MarkdownEditor {this.renderEditor()}
ref='content'
styleName='body-noteEditor'
config={config}
value={this.state.note.content}
storageKey={this.state.note.storage}
onChange={(e) => this.handleChange(e)}
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
/>
</div> </div>
<StatusBar <StatusBar
@@ -409,7 +442,8 @@ MarkdownNoteDetail.propTypes = {
style: PropTypes.shape({ style: PropTypes.shape({
left: PropTypes.number left: PropTypes.number
}), }),
ignorePreviewPointerEvents: PropTypes.bool ignorePreviewPointerEvents: PropTypes.bool,
confirmDeletion: PropTypes.bool.isRequired
} }
export default CSSModules(MarkdownNoteDetail, styles) export default CSSModules(MarkdownNoteDetail, styles)

View File

@@ -12,18 +12,13 @@
padding-bottom 3px padding-bottom 3px
.control-lockButton .control-lockButton
top 160px top 150px
margin-bottom 10px topBarButtonRight()
topBarButtonLight()
.trashed-infopanel .trashed-infopanel
top 40px top 40px
position relative position relative
.control-fullScreenButton
top 80px
topBarButtonLight()
.body .body
absolute left right absolute left right
left 0 left 0
@@ -33,7 +28,7 @@
margin 0 45px margin 0 45px
.body-noteEditor .body-noteEditor
absolute top bottom left right absolute top bottom left right
body[data-theme="white"] body[data-theme="white"]
.root .root
box-shadow $note-detail-box-shadow box-shadow $note-detail-box-shadow
@@ -43,7 +38,7 @@ body[data-theme="dark"]
.root .root
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
box-shadow none box-shadow none
border none border-left 1px solid $ui-dark-borderColor
.control-lockButton .control-lockButton
topBarButtonDark() topBarButtonDark()
@@ -53,3 +48,9 @@ body[data-theme="dark"]
.control-fullScreenButton .control-fullScreenButton
topBarButtonDark() topBarButtonDark()
body[data-theme="solarized-dark"]
.root
border-left 1px solid $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteDetail-backgroundColor

View File

@@ -95,4 +95,10 @@ body[data-theme="dark"]
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
.undo-button .undo-button
topBarButtonDark() topBarButtonDark()
body[data-theme="solarized-dark"]
.info
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteDetail-backgroundColor

View File

@@ -10,6 +10,7 @@ const PermanentDeleteButton = ({
onClick={(e) => onClick(e)} onClick={(e) => onClick(e)}
> >
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' /> <img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
<span styleName='tooltip'>Permanent Delete</span>
</button> </button>
) )

View File

@@ -11,6 +11,7 @@ import dataApi from 'browser/main/lib/dataApi'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
import ee from 'browser/main/lib/eventEmitter' import ee from 'browser/main/lib/eventEmitter'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import SnippetTab from 'browser/components/SnippetTab' import SnippetTab from 'browser/components/SnippetTab'
import StatusBar from '../StatusBar' import StatusBar from '../StatusBar'
import context from 'browser/lib/context' import context from 'browser/lib/context'
@@ -175,38 +176,37 @@ class SnippetNoteDetail extends React.Component {
handleTrashButtonClick (e) { handleTrashButtonClick (e) {
const { note } = this.state const { note } = this.state
const { isTrashed } = note const { isTrashed } = note
const { confirmDeletion } = this.props
if (isTrashed) { if (isTrashed) {
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { if (confirmDeletion(true)) {
type: 'warning', const {note, dispatch} = this.props
message: 'Confirm note deletion', dataApi
detail: 'This will permanently remove this note.', .deleteNote(note.storage, note.key)
buttons: ['Confirm', 'Cancel'] .then((data) => {
}) const dispatchHandler = () => {
if (dialogueButtonIndex === 1) return dispatch({
const { note, dispatch } = this.props type: 'DELETE_NOTE',
dataApi storageKey: data.storageKey,
.deleteNote(note.storage, note.key) noteKey: data.noteKey
.then((data) => { })
const dispatchHandler = () => { }
dispatch({ ee.once('list:moved', dispatchHandler)
type: 'DELETE_NOTE', })
storageKey: data.storageKey, }
noteKey: data.noteKey
})
}
ee.once('list:moved', dispatchHandler)
})
} else { } else {
note.isTrashed = true if (confirmDeletion()) {
note.isTrashed = true
this.setState({ this.setState({
note note
}, () => { }, () => {
this.save() this.save()
}) })
ee.emit('list:next')
}
} }
ee.emit('list:next')
} }
handleUndoButtonClick (e) { handleUndoButtonClick (e) {
@@ -236,6 +236,27 @@ class SnippetNoteDetail extends React.Component {
}) })
} }
handleTabDragStart (e, index) {
e.dataTransfer.setData('text/plain', index)
}
handleTabDrop (e, index) {
const oldIndex = parseInt(e.dataTransfer.getData('text'))
const snippets = this.state.note.snippets.slice()
const draggedSnippet = snippets[oldIndex]
snippets[oldIndex] = snippets[index]
snippets[index] = draggedSnippet
const snippetIndex = index
const note = Object.assign({}, this.state.note, {snippets})
this.setState({ note, snippetIndex }, () => {
this.save()
this.refs['code-' + index].reload()
this.refs['code-' + oldIndex].reload()
})
}
handleTabDeleteButtonClick (e, index) { handleTabDeleteButtonClick (e, index) {
if (this.state.note.snippets.length > 1) { if (this.state.note.snippets.length > 1) {
if (this.state.note.snippets[index].content.trim().length > 0) { if (this.state.note.snippets[index].content.trim().length > 0) {
@@ -359,7 +380,7 @@ class SnippetNoteDetail extends React.Component {
handleModeButtonClick (e, index) { handleModeButtonClick (e, index) {
const menu = new Menu() const menu = new Menu()
CodeMirror.modeInfo.forEach((mode) => { CodeMirror.modeInfo.sort(function (a, b) { return a.name.localeCompare(b.name) }).forEach((mode) => {
menu.append(new MenuItem({ menu.append(new MenuItem({
label: mode.name, label: mode.name,
click: (e) => this.handleModeOptionClick(index, mode.name)(e) click: (e) => this.handleModeOptionClick(index, mode.name)(e)
@@ -511,6 +532,8 @@ class SnippetNoteDetail extends React.Component {
onDelete={(e) => this.handleTabDeleteButtonClick(e, index)} onDelete={(e) => this.handleTabDeleteButtonClick(e, index)}
onRename={(name) => this.renameSnippetByIndex(index, name)} onRename={(name) => this.renameSnippetByIndex(index, name)}
isDeletable={note.snippets.length > 1} isDeletable={note.snippets.length > 1}
onDragStart={(e) => this.handleTabDragStart(e, index)}
onDrop={(e) => this.handleTabDrop(e, index)}
/> />
}) })
@@ -542,6 +565,7 @@ class SnippetNoteDetail extends React.Component {
indentType={config.editor.indentType} indentType={config.editor.indentType}
indentSize={editorIndentSize} indentSize={editorIndentSize}
keyMap={config.editor.keyMap} keyMap={config.editor.keyMap}
scrollPastEnd={config.editor.scrollPastEnd}
onChange={(e) => this.handleCodeChange(index)(e)} onChange={(e) => this.handleCodeChange(index)(e)}
ref={'code-' + index} ref={'code-' + index}
/> />
@@ -579,6 +603,7 @@ class SnippetNoteDetail extends React.Component {
createdAt={formatDate(note.createdAt)} createdAt={formatDate(note.createdAt)}
exportAsMd={this.showWarning} exportAsMd={this.showWarning}
exportAsTxt={this.showWarning} exportAsTxt={this.showWarning}
exportAsHtml={this.showWarning}
/> />
</div> </div>
</div> </div>
@@ -610,7 +635,7 @@ class SnippetNoteDetail extends React.Component {
isActive={note.isStarred} isActive={note.isStarred}
/> />
<button styleName='control-fullScreenButton' <button styleName='control-fullScreenButton' title='Fullscreen'
onMouseDown={(e) => this.handleFullScreenButton(e)}> onMouseDown={(e) => this.handleFullScreenButton(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' /> <img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
</button> </button>
@@ -705,7 +730,8 @@ SnippetNoteDetail.propTypes = {
style: PropTypes.shape({ style: PropTypes.shape({
left: PropTypes.number left: PropTypes.number
}), }),
ignorePreviewPointerEvents: PropTypes.bool ignorePreviewPointerEvents: PropTypes.bool,
confirmDeletion: PropTypes.bool.isRequired
} }
export default CSSModules(SnippetNoteDetail, styles) export default CSSModules(SnippetNoteDetail, styles)

View File

@@ -69,7 +69,7 @@
.control-fullScreenButton .control-fullScreenButton
top 80px top 80px
margin-bottom 10px margin-bottom 10px
topBarButtonLight() topBarButtonRight()
body[data-theme="white"] body[data-theme="white"]
.root .root
@@ -78,7 +78,7 @@ body[data-theme="white"]
body[data-theme="dark"] body[data-theme="dark"]
.root .root
border none border-left 1px solid $ui-dark-borderColor
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
box-shadow none box-shadow none
@@ -109,3 +109,20 @@ body[data-theme="dark"]
.control-fullScreenButton .control-fullScreenButton
topBarButtonDark() topBarButtonDark()
body[data-theme="solarized-dark"]
.root
border-left 1px solid $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteDetail-backgroundColor
.body
background-color $ui-solarized-dark-noteDetail-backgroundColor
.body .description textarea
background-color $ui-solarized-dark-noteDetail-backgroundColor
color $ui-solarized-dark-text-color
border 1px solid $ui-solarized-dark-borderColor
.tabList
background-color $ui-solarized-dark-noteDetail-backgroundColor
color $ui-solarized-dark-text-color

View File

@@ -46,14 +46,14 @@ class StarButton extends React.Component {
onMouseDown={(e) => this.handleMouseDown(e)} onMouseDown={(e) => this.handleMouseDown(e)}
onMouseUp={(e) => this.handleMouseUp(e)} onMouseUp={(e) => this.handleMouseUp(e)}
onMouseLeave={(e) => this.handleMouseLeave(e)} onMouseLeave={(e) => this.handleMouseLeave(e)}
onClick={this.props.onClick} onClick={this.props.onClick}>
>
<img styleName='icon' <img styleName='icon'
src={this.state.isActive || this.props.isActive src={this.state.isActive || this.props.isActive
? '../resources/icon/icon-starred.svg' ? '../resources/icon/icon-starred.svg'
: '../resources/icon/icon-star.svg' : '../resources/icon/icon-star.svg'
} }
/> />
<span styleName='tooltip'>Star</span>
</button> </button>
) )
} }

View File

@@ -1,9 +1,25 @@
.root .root
top 45px top 45px
topBarButtonLight() topBarButtonRight()
&:hover &:hover
transition 0.2s transition 0.2s
color alpha($ui-favorite-star-button-color, 0.6) color alpha($ui-favorite-star-button-color, 0.6)
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
right 0
width 100%
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.root--active .root--active
@extend .root @extend .root

View File

@@ -6,6 +6,7 @@
width 100% width 100%
overflow-x scroll overflow-x scroll
white-space nowrap white-space nowrap
margin-right 10px
.root::-webkit-scrollbar .root::-webkit-scrollbar
display none display none
@@ -63,4 +64,20 @@ body[data-theme="dark"]
.newTag .newTag
border-color none border-color none
background-color transparent background-color transparent
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.tag
background-color $ui-solarized-dark-tag-backgroundColor
.tag-removeButton
border-color $ui-button--focus-borderColor
background-color transparent
.tag-label
color $ui-solarized-dark-text-color
.newTag
border-color none
background-color transparent
color $ui-solarized-dark-text-color

View File

@@ -0,0 +1,25 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './ToggleModeButton.styl'
const ToggleModeButton = ({
onClick, editorType
}) => (
<div styleName='control-toggleModeButton'>
<div styleName={editorType === 'SPLIT' ? 'active' : 'non-active'} onClick={() => onClick('SPLIT')}>
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-split-on.svg' : '../resources/icon/icon-mode-split-on-active.svg'} />
</div>
<div styleName={editorType === 'EDITOR_PREVIEW' ? 'active' : 'non-active'} onClick={() => onClick('EDITOR_PREVIEW')}>
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-markdown-off-active.svg' : '../resources/icon/icon-mode-markdown-off.svg'} />
</div>
<span styleName='tooltip'>Toggle Mode</span>
</div>
)
ToggleModeButton.propTypes = {
onClick: PropTypes.func.isRequired,
editorType: PropTypes.string.Required
}
export default CSSModules(ToggleModeButton, styles)

View File

@@ -0,0 +1,61 @@
.control-toggleModeButton
border 1px solid #eee
height 34px
display flex
align-items center
div
width 40px
height 100%
background-color #f9f9f9
display flex
align-items center
justify-content center
cursor pointer
&:first-child
border-right 1px solid #eee
.active
background-color #fff
box-shadow 2px 0px 7px #eee
z-index 1
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 47px
right 11px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="dark"]
.control-fullScreenButton
topBarButtonDark()
.control-toggleModeButton
border 1px solid #444444
div
background-color $ui-dark-noteDetail-backgroundColor
&:first-child
border-right 1px solid #444444
.active
background-color #3A404C
box-shadow 2px 0px 7px #444444
body[data-theme="solarized-dark"]
.control-toggleModeButton
border 1px solid #586E75
div
background-color $ui-solarized-dark-noteDetail-backgroundColor
&:first-child
border-right 1px solid #586E75
.active
background-color #002B36
box-shadow 2px 0px 7px #222222

View File

@@ -10,6 +10,7 @@ const TrashButton = ({
onClick={(e) => onClick(e)} onClick={(e) => onClick(e)}
> >
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' /> <img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
<span styleName='tooltip'>Trash</span>
</button> </button>
) )

View File

@@ -1,11 +1,25 @@
.control-trashButton .control-trashButton
top 120px top 115px
margin-bottom 10px topBarButtonRight()
topBarButtonLight() &:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
right 0
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.control-trashButton--in-trash .control-trashButton--in-trash
top 60px top 60px
topBarButtonLight() topBarButtonRight()
.trashButton .trashButton
padding 0px padding 0px

View File

@@ -32,6 +32,26 @@ class Detail extends React.Component {
ee.off('detail:delete', this.deleteHandler) ee.off('detail:delete', this.deleteHandler)
} }
confirmDeletion (permanent) {
if (this.props.config.ui.confirmDeletion || permanent) {
const electron = require('electron')
const { remote } = electron
const { dialog } = remote
const alertConfig = {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
}
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), alertConfig)
return dialogueButtonIndex === 0
}
return true
}
render () { render () {
const { location, data, config } = this.props const { location, data, config } = this.props
let note = null let note = null
@@ -64,6 +84,7 @@ class Detail extends React.Component {
<SnippetNoteDetail <SnippetNoteDetail
note={note} note={note}
config={config} config={config}
confirmDeletion={(permanent) => this.confirmDeletion(permanent)}
ref='root' ref='root'
{..._.pick(this.props, [ {..._.pick(this.props, [
'dispatch', 'dispatch',
@@ -80,6 +101,7 @@ class Detail extends React.Component {
<MarkdownNoteDetail <MarkdownNoteDetail
note={note} note={note}
config={config} config={config}
confirmDeletion={(permanent) => this.confirmDeletion(permanent)}
ref='root' ref='root'
{..._.pick(this.props, [ {..._.pick(this.props, [
'dispatch', 'dispatch',

View File

@@ -10,10 +10,13 @@ import Detail from './Detail'
import dataApi from 'browser/main/lib/dataApi' import dataApi from 'browser/main/lib/dataApi'
import _ from 'lodash' import _ from 'lodash'
import ConfigManager from 'browser/main/lib/ConfigManager' import ConfigManager from 'browser/main/lib/ConfigManager'
import modal from 'browser/main/lib/modal'
import InitModal from 'browser/main/modals/InitModal'
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig' import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import { hashHistory } from 'react-router'
import store from 'browser/main/store'
const path = require('path')
const electron = require('electron')
const { remote } = electron
class Main extends React.Component { class Main extends React.Component {
@@ -48,6 +51,91 @@ class Main extends React.Component {
} }
} }
init () {
dataApi
.addStorage({
name: 'My Storage',
path: path.join(remote.app.getPath('home'), 'Boostnote')
})
.then((data) => {
return data
})
.then((data) => {
if (data.storage.folders[0] != null) {
return data
} else {
return dataApi
.createFolder(data.storage.key, {
color: '#1278BD',
name: 'Default'
})
.then((_data) => {
return {
storage: _data.storage,
notes: data.notes
}
})
}
})
.then((data) => {
console.log(data)
store.dispatch({
type: 'ADD_STORAGE',
storage: data.storage,
notes: data.notes
})
const defaultSnippetNote = dataApi
.createNote(data.storage.key, {
type: 'SNIPPET_NOTE',
folder: data.storage.folders[0].key,
title: 'Snippet note example',
description: 'Snippet note example\nYou can store a series of snippets as a single note, like Gist.',
snippets: [
{
name: 'example.html',
mode: 'html',
content: '<html>\n<body>\n<h1 id=\'hello\'>Enjoy Boostnote!</h1>\n</body>\n</html>'
},
{
name: 'example.js',
mode: 'javascript',
content: 'var boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)'
}
]
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
const defaultMarkdownNote = dataApi
.createNote(data.storage.key, {
type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote!',
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
return Promise.resolve(defaultSnippetNote)
.then(defaultMarkdownNote)
.then(() => data.storage)
})
.then((storage) => {
hashHistory.push('/storages/' + storage.key)
})
.catch((err) => {
throw err
})
}
componentDidMount () { componentDidMount () {
const { dispatch, config } = this.props const { dispatch, config } = this.props
@@ -55,6 +143,8 @@ class Main extends React.Component {
document.body.setAttribute('data-theme', 'dark') document.body.setAttribute('data-theme', 'dark')
} else if (config.ui.theme === 'white') { } else if (config.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white') document.body.setAttribute('data-theme', 'white')
} else if (config.ui.theme === 'solarized-dark') {
document.body.setAttribute('data-theme', 'solarized-dark')
} else { } else {
document.body.setAttribute('data-theme', 'default') document.body.setAttribute('data-theme', 'default')
} }
@@ -69,7 +159,7 @@ class Main extends React.Component {
}) })
if (data.storages.length < 1) { if (data.storages.length < 1) {
modal.open(InitModal) this.init()
} }
}) })

View File

@@ -71,3 +71,7 @@ body[data-theme="dark"]
.control-newNoteButton-tooltip .control-newNoteButton-tooltip
darkTooltip() darkTooltip()
body[data-theme="solarized-dark"]
.root, .root--expanded
background-color $ui-solarized-dark-noteList-backgroundColor

View File

@@ -88,4 +88,29 @@ body[data-theme="dark"]
.control-button--active .control-button--active
color $ui-dark-text-color color $ui-dark-text-color
&:active &:active
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.root
border-color $ui-solarized-dark-borderColor
background-color $ui-solarized-dark-noteList-backgroundColor
.control
background-color $ui-solarized-dark-noteList-backgroundColor
border-color $ui-solarized-dark-borderColor
.control-sortBy-select
&:hover
transition 0.2s
color $ui-solarized-dark-text-color
.control-button
color $ui-solarized-dark-inactive-text-color
&:hover
color $ui-solarized-dark-text-color
.control-button--active
color $ui-solarized-dark-text-color
&:active
color $ui-solarized-dark-text-color

View File

@@ -12,7 +12,7 @@ import NoteItemSimple from 'browser/components/NoteItemSimple'
import searchFromNotes from 'browser/lib/search' import searchFromNotes from 'browser/lib/search'
import fs from 'fs' import fs from 'fs'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
import markdown from 'browser/lib/markdown' import markdown from 'browser/lib/markdownTextHelper'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import store from 'browser/main/store' import store from 'browser/main/store'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
@@ -235,18 +235,8 @@ class NoteList extends React.Component {
return return
} }
const { router } = this.context const selectedNoteKeys = [noteHash]
const { location } = this.props this.focusNote(selectedNoteKeys, noteHash)
let targetIndex = this.getTargetIndex()
if (targetIndex < 0) targetIndex = 0
const selectedNoteKeys = []
const nextNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
selectedNoteKeys.push(nextNoteKey)
this.focusNote(selectedNoteKeys, nextNoteKey)
ee.emit('list:moved') ee.emit('list:moved')
} }
@@ -584,22 +574,29 @@ class NoteList extends React.Component {
filepaths.forEach((filepath) => { filepaths.forEach((filepath) => {
fs.readFile(filepath, (err, data) => { fs.readFile(filepath, (err, data) => {
if (err) throw Error('File reading error: ', err) if (err) throw Error('File reading error: ', err)
const content = data.toString()
const newNote = { fs.stat(filepath, (err, {mtime, birthtime}) => {
content: content, if (err) throw Error('File stat reading error: ', err)
folder: folder.key,
title: markdown.strip(findNoteTitle(content)), const content = data.toString()
type: 'MARKDOWN_NOTE' const newNote = {
} content: content,
dataApi.createNote(storage.key, newNote) folder: folder.key,
.then((note) => { title: markdown.strip(findNoteTitle(content)),
dispatch({ type: 'MARKDOWN_NOTE',
type: 'UPDATE_NOTE', createdAt: birthtime,
note: note updatedAt: mtime
}) }
hashHistory.push({ dataApi.createNote(storage.key, newNote)
pathname: location.pathname, .then((note) => {
query: {key: getNoteKey(note)} dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: getNoteKey(note)}
})
}) })
}) })
}) })
@@ -717,6 +714,7 @@ class NoteList extends React.Component {
handleNoteContextMenu={this.handleNoteContextMenu.bind(this)} handleNoteContextMenu={this.handleNoteContextMenu.bind(this)}
handleNoteClick={this.handleNoteClick.bind(this)} handleNoteClick={this.handleNoteClick.bind(this)}
handleDragStart={this.handleDragStart.bind(this)} handleDragStart={this.handleDragStart.bind(this)}
pathname={location.pathname}
/> />
) )
}) })

View File

@@ -0,0 +1,24 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SwitchButton.styl'
const ListButton = ({
onClick, isTagActive
}) => (
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={onClick}>
<img src={isTagActive
? '../resources/icon/icon-list.svg'
: '../resources/icon/icon-list-active.svg'
}
/>
<span styleName='tooltip'>Notes</span>
</button>
)
ListButton.propTypes = {
onClick: PropTypes.func.isRequired,
isTagActive: PropTypes.bool.isRequired
}
export default CSSModules(ListButton, styles)

View File

@@ -0,0 +1,19 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './PreferenceButton.styl'
const PreferenceButton = ({
onClick
}) => (
<button styleName='top-menu-preference' onClick={(e) => onClick(e)}>
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
<span styleName='tooltip'>Preferences</span>
</button>
)
PreferenceButton.propTypes = {
onClick: PropTypes.func.isRequired
}
export default CSSModules(PreferenceButton, styles)

View File

@@ -0,0 +1,51 @@
.top-menu-preference
navButtonColor()
position absolute
top 22px
right 10px
width 2em
background-color transparent
&:hover
color $ui-button-default--active-backgroundColor
background-color transparent
.tooltip
opacity 1
&:active, &:active:hover
color $ui-button-default--active-backgroundColor
body[data-theme="white"]
.top-menu-preference
navWhiteButtonColor()
background-color transparent
&:hover
color #0B99F1
background-color transparent
&:active, &:active:hover
color #0B99F1
background-color transparent
body[data-theme="dark"]
.top-menu-preference
navDarkButtonColor()
background-color transparent
&:active
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
.tooltip
tooltip()
position absolute
pointer-events none
top 26px
left -20px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s

View File

@@ -11,19 +11,6 @@
.top .top
padding-bottom 15px padding-bottom 15px
.top-menu-preference
navButtonColor()
position absolute
top 22px
right 10px
width 2em
background-color transparent
&:hover
color $ui-button-default--active-backgroundColor
background-color transparent
&:active, &:active:hover
color $ui-button-default--active-backgroundColor
.switch-buttons .switch-buttons
background-color transparent background-color transparent
border 0 border 0
@@ -31,21 +18,7 @@
display flex display flex
text-align center text-align center
.non-active-button
color $ui-inactive-text-color
font-size 16px
border 0
background-color transparent
transition 0.2s
display flex
text-align center
margin-right 4px;
&:hover
color alpha(#239F86, 60%)
.active-button
@extend .non-active-button
color $ui-button-default--active-backgroundColor
.top-menu-label .top-menu-label
margin-left 5px margin-left 5px
@@ -109,57 +82,16 @@ body[data-theme="white"]
background-color #f9f9f9 background-color #f9f9f9
color $ui-text-color color $ui-text-color
.top-menu-preference
navWhiteButtonColor()
background-color transparent
&:hover
color #0B99F1
background-color transparent
&:active, &:active:hover
color #0B99F1
background-color transparent
.non-active-button
color $ui-inactive-text-color
&:hover
color alpha(#0B99F1, 60%)
.tag-title
p
color $ui-text-color
.non-active-button
&:hover
color alpha(#0B99F1, 60%)
.active-button
@extend .non-active-button
color #0B99F1
body[data-theme="dark"] body[data-theme="dark"]
.root, .root--folded .root, .root--folded
border-color $ui-dark-borderColor border-right 1px solid $ui-dark-borderColor
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
color $ui-dark-text-color color $ui-dark-text-color
.top .top
border-color $ui-dark-borderColor border-color $ui-dark-borderColor
.top-menu-preference body[data-theme="solarized-dark"]
navDarkButtonColor() .root, .root--folded
background-color transparent background-color $ui-solarized-dark-backgroundColor
&:active border-right 1px solid $ui-solarized-dark-borderColor
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
background-color transparent
.non-active-button
color alpha($ui-dark-text-color, 60%)
&:hover
color alpha(#0B99F1, 60%)
.tag-title
p
color alpha($ui-dark-text-color, 60%)

View File

@@ -10,6 +10,7 @@ import dataApi from 'browser/main/lib/dataApi'
import StorageItemChild from 'browser/components/StorageItem' import StorageItemChild from 'browser/components/StorageItem'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import _ from 'lodash' import _ from 'lodash'
import * as path from 'path'
const { remote } = require('electron') const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote const { Menu, MenuItem, dialog } = remote
@@ -24,18 +25,20 @@ class StorageItem extends React.Component {
} }
handleHeaderContextMenu (e) { handleHeaderContextMenu (e) {
const menu = new Menu() const menu = Menu.buildFromTemplate([
menu.append(new MenuItem({ {
label: 'Add Folder', label: 'Add Folder',
click: (e) => this.handleAddFolderButtonClick(e) click: (e) => this.handleAddFolderButtonClick(e)
})) },
menu.append(new MenuItem({ {
type: 'separator' type: 'separator'
})) },
menu.append(new MenuItem({ {
label: 'Unlink Storage', label: 'Unlink Storage',
click: (e) => this.handleUnlinkStorageClick(e) click: (e) => this.handleUnlinkStorageClick(e)
})) }
])
menu.popup() menu.popup()
} }
@@ -89,18 +92,36 @@ class StorageItem extends React.Component {
} }
handleFolderButtonContextMenu (e, folder) { handleFolderButtonContextMenu (e, folder) {
const menu = new Menu() const menu = Menu.buildFromTemplate([
menu.append(new MenuItem({ {
label: 'Rename Folder', label: 'Rename Folder',
click: (e) => this.handleRenameFolderClick(e, folder) click: (e) => this.handleRenameFolderClick(e, folder)
})) },
menu.append(new MenuItem({ {
type: 'separator' type: 'separator'
})) },
menu.append(new MenuItem({ {
label: 'Delete Folder', label: 'Export Folder',
click: (e) => this.handleFolderDeleteClick(e, folder) submenu: [
})) {
label: 'Export as txt',
click: (e) => this.handleExportFolderClick(e, folder, 'txt')
},
{
label: 'Export as md',
click: (e) => this.handleExportFolderClick(e, folder, 'md')
}
]
},
{
type: 'separator'
},
{
label: 'Delete Folder',
click: (e) => this.handleFolderDeleteClick(e, folder)
}
])
menu.popup() menu.popup()
} }
@@ -112,6 +133,31 @@ class StorageItem extends React.Component {
}) })
} }
handleExportFolderClick (e, folder, fileType) {
const options = {
properties: ['openDirectory', 'createDirectory'],
buttonLabel: 'Select directory',
title: 'Select a folder to export the files to',
multiSelections: false
}
dialog.showOpenDialog(remote.getCurrentWindow(), options,
(paths) => {
if (paths && paths.length === 1) {
const { storage, dispatch } = this.props
dataApi
.exportFolder(storage.key, folder.key, fileType, paths[0])
.then((data) => {
dispatch({
type: 'EXPORT_FOLDER',
storage: data.storage,
folderKey: data.folderKey,
fileType: data.fileType
})
})
}
})
}
handleFolderDeleteClick (e, folder) { handleFolderDeleteClick (e, folder) {
const index = dialog.showMessageBox(remote.getCurrentWindow(), { const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning', type: 'warning',

View File

@@ -179,4 +179,8 @@ body[data-theme="dark"]
background-color alpha($ui-dark-button--active-backgroundColor, 60%) background-color alpha($ui-dark-button--active-backgroundColor, 60%)
&:active, &:active:hover &:active, &:active:hover
color $ui-dark-text-color color $ui-dark-text-color
background-color $ui-dark-button--active-backgroundColor background-color $ui-dark-button--active-backgroundColor

View File

@@ -0,0 +1,59 @@
.non-active-button
color $ui-inactive-text-color
font-size 16px
border 0
background-color transparent
transition 0.2s
display flex
text-align center
margin-right 4px
position relative
&:hover
color alpha(#239F86, 60%)
.tooltip
opacity 1
.active-button
@extend .non-active-button
color $ui-button-default--active-backgroundColor
.tooltip
tooltip()
position absolute
pointer-events none
top 22px
left -2px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="white"]
.non-active-button
color $ui-inactive-text-color
&:hover
color alpha(#0B99F1, 60%)
.tag-title
p
color $ui-text-color
.non-active-button
&:hover
color alpha(#0B99F1, 60%)
.active-button
@extend .non-active-button
color #0B99F1
body[data-theme="dark"]
.non-active-button
color alpha($ui-dark-text-color, 60%)
&:hover
color alpha(#0B99F1, 60%)
.tag-title
p
color alpha($ui-dark-text-color, 60%)

View File

@@ -0,0 +1,24 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SwitchButton.styl'
const TagButton = ({
onClick, isTagActive
}) => (
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={onClick}>
<img src={isTagActive
? '../resources/icon/icon-tag-active.svg'
: '../resources/icon/icon-tag.svg'
}
/>
<span styleName='tooltip'>Tags</span>
</button>
)
TagButton.propTypes = {
onClick: PropTypes.func.isRequired,
isTagActive: PropTypes.bool.isRequired
}
export default CSSModules(TagButton, styles)

View File

@@ -11,6 +11,9 @@ import SideNavFilter from 'browser/components/SideNavFilter'
import StorageList from 'browser/components/StorageList' import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton' import NavToggleButton from 'browser/components/NavToggleButton'
import EventEmitter from 'browser/main/lib/eventEmitter' import EventEmitter from 'browser/main/lib/eventEmitter'
import PreferenceButton from './PreferenceButton'
import ListButton from './ListButton'
import TagButton from './TagButton'
class SideNav extends React.Component { class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7 // TODO: should not use electron stuff v0.7
@@ -162,27 +165,11 @@ class SideNav extends React.Component {
> >
<div styleName='top'> <div styleName='top'>
<div styleName='switch-buttons'> <div styleName='switch-buttons'>
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}> <ListButton onClick={this.handleSwitchFoldersButtonClick.bind(this)} isTagActive={isTagActive} />
<img src={isTagActive <TagButton onClick={this.handleSwitchTagsButtonClick.bind(this)} isTagActive={isTagActive} />
? '../resources/icon/icon-list.svg'
: '../resources/icon/icon-list-active.svg'
}
/>
</button>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>
<img src={isTagActive
? '../resources/icon/icon-tag-active.svg'
: '../resources/icon/icon-tag.svg'
}
/>
</button>
</div> </div>
<div> <div>
<button styleName='top-menu-preference' <PreferenceButton onClick={this.handleMenuButtonClick} />
onClick={(e) => this.handleMenuButtonClick(e)}
>
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
</button>
</div> </div>
</div> </div>
{this.SideNavComponent(isFolded, storageList)} {this.SideNavComponent(isFolded, storageList)}

View File

@@ -63,7 +63,7 @@ class StatusBar extends React.Component {
{status.updateReady {status.updateReady
? <button onClick={this.updateApp} styleName='update'> ? <button onClick={this.updateApp} styleName='update'>
<i styleName='update-icon' className='fa fa-cloud-download' /> Ready to Update! <i styleName='update-icon' className='fa fa-cloud-download' /> Ready to Update!
</button> </button>
: null : null
} }
</div> </div>

View File

@@ -185,3 +185,26 @@ body[data-theme="dark"]
.control-newPostButton-tooltip .control-newPostButton-tooltip
darkTooltip() darkTooltip()
body[data-theme="solarized-dark"]
.root, .root--expanded
background-color $ui-solarized-dark-noteList-backgroundColor
.control
border-color $ui-solarized-dark-borderColor
.control-search
background-color $ui-solarized-dark-noteList-backgroundColor
.control-search-icon
absolute top bottom left
line-height 32px
width 35px
color $ui-solarized-dark-inactive-text-color
background-color $ui-solarized-dark-noteList-backgroundColor
.control-search-input
background-color $ui-solarized-dark-noteList-backgroundColor
input
background-color $ui-solarized-dark-noteList-backgroundColor
color $ui-solarized-dark-text-color

View File

@@ -1,4 +1,5 @@
global-reset() global-reset()
@import '../styles/vars.styl'
DEFAULT_FONTS = 'OpenSans', helvetica, arial, sans-serif DEFAULT_FONTS = 'OpenSans', helvetica, arial, sans-serif
@@ -84,10 +85,14 @@ modalBackColor = white
absolute top left bottom right absolute top left bottom right
background-color modalBackColor background-color modalBackColor
z-index modalZIndex + 1 z-index modalZIndex + 1
body[data-theme="dark"] body[data-theme="dark"]
.ModalBase .ModalBase
.modalBack .modalBack
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
.sortableItemHelper
color: $ui-dark-text-color
.CodeMirror .CodeMirror
font-family inherit !important font-family inherit !important
@@ -107,6 +112,11 @@ body[data-theme="dark"]
.sortableItemHelper .sortableItemHelper
z-index modalZIndex + 5 z-index modalZIndex + 5
body[data-theme="dark"] body[data-theme="solarized-dark"]
.ModalBase
.modalBack
background-color $ui-solarized-dark-backgroundColor
.sortableItemHelper .sortableItemHelper
color: $ui-dark-text-color color: $ui-solarized-dark-text-color

View File

@@ -7,7 +7,7 @@ const os = require('os')
let mobileAnalyticsClient let mobileAnalyticsClient
AWS.config.region = 'us-east-1' AWS.config.region = 'us-east-1'
if (process.env.NODE_ENV === 'production' && ConfigManager.default.get().amaEnabled) { if (!getSendEventCond()) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({ AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx' IdentityPoolId: 'us-east-1:xxxxxxxxxxxxxxxxxxxxxxxxx'
}) })
@@ -34,8 +34,15 @@ function convertPlatformName (platformName) {
} }
} }
function getSendEventCond () {
const isDev = process.env.NODE_ENV !== 'production'
const isDisable = !ConfigManager.default.get().amaEnabled
const isOffline = !window.navigator.onLine
return isDev || isDisable || isOffline
}
function initAwsMobileAnalytics () { function initAwsMobileAnalytics () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return if (getSendEventCond()) return
AWS.config.credentials.get((err) => { AWS.config.credentials.get((err) => {
if (!err) { if (!err) {
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId) console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
@@ -46,7 +53,7 @@ function initAwsMobileAnalytics () {
} }
function recordDynamicCustomEvent (type, options = {}) { function recordDynamicCustomEvent (type, options = {}) {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return if (getSendEventCond()) return
try { try {
mobileAnalyticsClient.recordEvent(type, options) mobileAnalyticsClient.recordEvent(type, options)
} catch (analyticsError) { } catch (analyticsError) {
@@ -57,7 +64,7 @@ function recordDynamicCustomEvent (type, options = {}) {
} }
function recordStaticCustomEvent () { function recordStaticCustomEvent () {
if (process.env.NODE_ENV !== 'production' || !ConfigManager.default.get().amaEnabled) return if (getSendEventCond()) return
try { try {
mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', { mobileAnalyticsClient.recordEvent('UI_COLOR_THEME', {
uiColorTheme: ConfigManager.default.get().ui.theme uiColorTheme: ConfigManager.default.get().ui.theme

View File

@@ -34,13 +34,19 @@ export const DEFAULT_CONFIG = {
fontFamily: win ? 'Segoe UI' : 'Monaco, Consolas', fontFamily: win ? 'Segoe UI' : 'Monaco, Consolas',
indentType: 'space', indentType: 'space',
indentSize: '2', indentSize: '2',
switchPreview: 'BLUR' // Available value: RIGHTCLICK, BLUR switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR
scrollPastEnd: false,
type: 'SPLIT'
}, },
preview: { preview: {
fontSize: '14', fontSize: '14',
fontFamily: win ? 'Segoe UI' : 'Lato', fontFamily: win ? 'Segoe UI' : 'Lato',
codeBlockTheme: 'dracula', codeBlockTheme: 'dracula',
lineNumber: true lineNumber: true,
latexInlineOpen: '$',
latexInlineClose: '$',
latexBlockOpen: '$$',
latexBlockClose: '$$'
} }
} }
@@ -110,6 +116,8 @@ function set (updates) {
document.body.setAttribute('data-theme', 'dark') document.body.setAttribute('data-theme', 'dark')
} else if (newConfig.ui.theme === 'white') { } else if (newConfig.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white') document.body.setAttribute('data-theme', 'white')
} else if (newConfig.ui.theme === 'solarized-dark') {
document.body.setAttribute('data-theme', 'solarized-dark')
} else { } else {
document.body.setAttribute('data-theme', 'default') document.body.setAttribute('data-theme', 'default')
} }

View File

@@ -66,12 +66,16 @@ function createNote (storageKey, input) {
} }
} }
} }
const noteData = Object.assign({}, input, { const noteData = Object.assign({},
key, {
createdAt: new Date(), createdAt: new Date(),
updatedAt: new Date(), updatedAt: new Date()
storage: storageKey },
}) input, // input may contain more accurate dates
{
key,
storage: storageKey
})
CSON.writeFileSync(path.join(storage.path, 'notes', key + '.cson'), _.omit(noteData, ['key', 'storage'])) CSON.writeFileSync(path.join(storage.path, 'notes', key + '.cson'), _.omit(noteData, ['key', 'storage']))

View File

@@ -0,0 +1,61 @@
import { findStorage } from 'browser/lib/findStorage'
import resolveStorageData from './resolveStorageData'
import resolveStorageNotes from './resolveStorageNotes'
import * as path from 'path'
import * as fs from 'fs'
/**
* @param {String} storageKey
* @param {String} folderKey
* @param {String} fileType
* @param {String} exportDir
*
* @return {Object}
* ```
* {
* storage: Object,
* folderKey: String,
* fileType: String,
* exportDir: String
* }
* ```
*/
function exportFolder (storageKey, folderKey, fileType, exportDir) {
let targetStorage
try {
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
return resolveStorageData(targetStorage)
.then(function assignNotes (storage) {
return resolveStorageNotes(storage)
.then((notes) => {
return {
storage,
notes
}
})
})
.then(function exportNotes (data) {
const { storage, notes } = data
notes
.filter(note => note.folder === folderKey && note.isTrashed === false && note.type === 'MARKDOWN_NOTE')
.forEach(snippet => {
const notePath = path.join(exportDir, `${snippet.title}.${fileType}`)
fs.writeFileSync(notePath, snippet.content)
})
return {
storage,
folderKey,
fileType,
exportDir
}
})
}
module.exports = exportFolder

View File

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

View File

@@ -29,7 +29,7 @@
width 490px width 490px
padding 0 5px padding 0 5px
margin 10px 0 margin 10px 0
border 1px solid #C9C9C9 // TODO: use variable. border 1px solid $ui-input--create-folder-modal
border-radius 2px border-radius 2px
background-color transparent background-color transparent
outline none outline none
@@ -68,7 +68,7 @@ body[data-theme="dark"]
color $ui-dark-text-color color $ui-dark-text-color
.control-folder-input .control-folder-input
border 1px solid #C9C9C9 // TODO: use variable. border 1px solid $ui-input--create-folder-modal
color white color white
.description .description
@@ -76,3 +76,29 @@ body[data-theme="dark"]
.control-confirmButton .control-confirmButton
colorDarkPrimaryButton() colorDarkPrimaryButton()
body[data-theme="solarized-dark"]
.root
modalSolarizedDark()
width 500px
height 270px
overflow hidden
position relative
.header
background-color transparent
border-color $ui-dark-borderColor
color $ui-solarized-dark-text-color
.control-folder-label
color $ui-solarized-dark-text-color
.control-folder-input
border 1px solid $ui-input--create-folder-modal
color white
.description
color $ui-inactive-text-color
.control-confirmButton
colorSolarizedDarkPrimaryButton()

View File

@@ -1,254 +0,0 @@
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InitModal.styl'
import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
import { hashHistory } from 'react-router'
import _ from 'lodash'
const CSON = require('@rokt33r/season')
const path = require('path')
const electron = require('electron')
const { remote } = electron
function browseFolder () {
const dialog = remote.dialog
const defaultPath = remote.app.getPath('home')
return new Promise((resolve, reject) => {
dialog.showOpenDialog({
title: 'Select Directory',
defaultPath,
properties: ['openDirectory', 'createDirectory']
}, function (targetPaths) {
if (targetPaths == null) return resolve('')
resolve(targetPaths[0])
})
})
}
class InitModal extends React.Component {
constructor (props) {
super(props)
this.state = {
path: path.join(remote.app.getPath('home'), 'Boostnote'),
migrationRequested: true,
isLoading: true,
data: null,
legacyStorageExists: false,
isSending: false
}
}
handlePathChange (e) {
this.setState({
path: e.target.value
})
}
componentDidMount () {
let data = null
try {
data = CSON.readFileSync(path.join(remote.app.getPath('userData'), 'local.json'))
} catch (err) {
console.error(err)
}
const newState = {
isLoading: false
}
if (data != null) {
newState.legacyStorageExists = true
newState.data = data
}
this.setState(newState, () => {
this.refs.createButton.focus()
})
}
handlePathBrowseButtonClick (e) {
browseFolder()
.then((targetPath) => {
if (targetPath.length > 0) {
this.setState({
path: targetPath
})
}
})
.catch((err) => {
console.error('BrowseFAILED')
console.error(err)
})
}
handleSubmitButtonClick (e) {
this.setState({
isSending: true
}, () => {
dataApi
.addStorage({
name: 'My Storage',
path: this.state.path
})
.then((data) => {
if (this.state.migrationRequested && _.isObject(this.state.data) && _.isArray(this.state.data.folders) && _.isArray(this.state.data.articles)) {
return dataApi.migrateFromV5Storage(data.storage.key, this.state.data)
}
return data
})
.then((data) => {
if (data.storage.folders[0] != null) {
return data
} else {
return dataApi
.createFolder(data.storage.key, {
color: '#1278BD',
name: 'Default'
})
.then((_data) => {
return {
storage: _data.storage,
notes: data.notes
}
})
}
})
.then((data) => {
console.log(data)
store.dispatch({
type: 'ADD_STORAGE',
storage: data.storage,
notes: data.notes
})
const defaultSnippetNote = dataApi
.createNote(data.storage.key, {
type: 'SNIPPET_NOTE',
folder: data.storage.folders[0].key,
title: 'Snippet note example',
description: 'Snippet note example\nYou can store a series of snippets as a single note, like Gist.',
snippets: [
{
name: 'example.html',
mode: 'html',
content: '<html>\n<body>\n<h1 id=\'hello\'>Enjoy Boostnote!</h1>\n</body>\n</html>'
},
{
name: 'example.js',
mode: 'javascript',
content: 'var boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)'
}
]
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
const defaultMarkdownNote = dataApi
.createNote(data.storage.key, {
type: 'MARKDOWN_NOTE',
folder: data.storage.folders[0].key,
title: 'Welcome to Boostnote!',
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
})
.then((note) => {
store.dispatch({
type: 'UPDATE_NOTE',
note: note
})
})
return Promise.resolve(defaultSnippetNote)
.then(defaultMarkdownNote)
.then(() => data.storage)
})
.then((storage) => {
hashHistory.push('/storages/' + storage.key)
this.props.close()
})
.catch((err) => {
this.setState({
isSending: false
})
throw err
})
})
}
handleMigrationRequestedChange (e) {
this.setState({
migrationRequested: e.target.checked
})
}
handleKeyDown (e) {
if (e.keyCode === 27) {
this.props.close()
}
}
render () {
if (this.state.isLoading) {
return <div styleName='root--loading'>
<i styleName='spinner' className='fa fa-spin fa-spinner' />
<div styleName='loadingMessage'>Preparing initialization...</div>
</div>
}
return (
<div styleName='root'
tabIndex='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='body'>
<div styleName='body-welcome'>
Welcome to Boostnote!
</div>
<div styleName='body-description'>
Please select a directory for data storage.
</div>
<div styleName='body-path'>
<input styleName='body-path-input'
placeholder='Select Folder'
value={this.state.path}
onChange={(e) => this.handlePathChange(e)}
/>
<button styleName='body-path-button'
onClick={(e) => this.handlePathBrowseButtonClick(e)}
>
...
</button>
</div>
{this.state.legacyStorageExists &&
<div styleName='body-migration'>
<label><input type='checkbox' checked={this.state.migrationRequested} onChange={(e) => this.handleMigrationRequestedChange(e)} /> Migrate old data from the legacy app v0.5</label>
</div>
}
<div styleName='body-control'>
<button styleName='body-control-createButton'
ref='createButton'
onClick={(e) => this.handleSubmitButtonClick(e)}
disabled={this.state.isSending}
>
{this.state.isSending
? <span>
<i className='fa fa-spin fa-spinner' /> Loading...
</span>
: 'CREATE'
}
</button>
</div>
</div>
</div>
)
}
}
InitModal.propTypes = {
}
export default CSSModules(InitModal, styles)

View File

@@ -1,76 +0,0 @@
.root
modal()
background-color #fff
max-width 100vw
max-height 100vh
overflow hidden
margin 0
padding 150px 0
position relative
.root--loading
@extend .root
text-align center
.spinner
font-size 100px
margin 35px auto
color $ui-text-color
.loadingMessage
color $ui-text-color
margin 15px auto 35px
.body
padding 30px
.body-welcome
text-align center
margin-bottom 25px
font-size 32px
color $ui-text-color
.body-description
font-size 16px
color $ui-text-color
text-align center
margin-bottom 25px
.body-path
margin 0 auto 25px
width 330px
.body-path-input
height 40px
vertical-align middle
width 300px
font-size 14px
border-style solid
border-width 1px 0 1px 1px
border-color $border-color
border-top-left-radius 2px
border-bottom-left-radius 2px
padding 0 5px
.body-path-button
height 42px
width 30px
font-size 16px
font-weight 600
border none
border-top-right-radius 2px
border-bottom-right-radius 2px
colorPrimaryButton()
vertical-align middle
.body-migration
margin 0 auto 25px
text-align center
.body-control
text-align center
.body-control-createButton
colorPrimaryButton()
font-size 14px
font-weight 600
border none
border-radius 2px
height 40px
padding 0 25px

View File

@@ -64,3 +64,20 @@ body[data-theme="dark"]
.description .description
color $ui-inactive-text-color color $ui-inactive-text-color
body[data-theme="solarized-dark"]
.root
background-color transparent
.header
color $ui-solarized-dark-text-color
.control-button
border-color $ui-solarized-dark-borderColor
color $ui-solarized-dark-text-color
background-color transparent
&:focus
colorDarkPrimaryButton()
.description
color $ui-solarized-dark-text-color

View File

@@ -76,8 +76,8 @@
color #1EC38B color #1EC38B
.error .error
color red color red
.warning
color #FFA500
.group-control-leftButton .group-control-leftButton
colorDefaultButton() colorDefaultButton()
@@ -127,6 +127,12 @@ colorDarkControl()
border-color $ui-dark-borderColor border-color $ui-dark-borderColor
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
color $ui-dark-text-color color $ui-dark-text-color
colorSolarizedDarkControl()
border none
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
body[data-theme="dark"] body[data-theme="dark"]
.root .root
@@ -154,3 +160,33 @@ body[data-theme="dark"]
.group-section-control .group-section-control
select, .group-section-control-input select, .group-section-control-input
colorDarkControl() colorDarkControl()
body[data-theme="solarized-dark"]
.root
color $ui-solarized-dark-text-color
.group-header
color $ui-solarized-dark-text-color
border-color $ui-solarized-dark-borderColor
.group-header2
color $ui-solarized-dark-text-color
.group-section-control-input
border-color $ui-solarized-dark-borderColor
.group-control
border-color $ui-solarized-dark-borderColor
.group-control-leftButton
colorDarkDefaultButton()
border-color $ui-solarized-dark-borderColor
.group-control-rightButton
colorSolarizedDarkPrimaryButton()
.group-hint
colorSolarizedDarkControl()
.group-section-control
select, .group-section-control-input
colorSolarizedDarkControl()

View File

@@ -27,4 +27,10 @@ p
body[data-theme="dark"] body[data-theme="dark"]
p p
color $ui-dark-text-color color $ui-dark-text-color
body[data-theme="solarized-dark"]
.root
color $ui-solarized-dark-text-color
p
color $ui-solarized-dark-text-color

View File

@@ -101,3 +101,28 @@ body[data-theme="dark"]
.folderItem-right-dangerButton .folderItem-right-dangerButton
colorDarkDangerButton() colorDarkDangerButton()
body[data-theme="solarized-dark"]
.folderItem
&:hover
background-color $ui-solarized-dark-button-backgroundColor
.folderItem-left-danger
color $danger-color
.folderItem-left-key
color $ui-dark-inactive-text-color
.folderItem-left-colorButton
colorSolarizedDarkPrimaryButton()
.folderItem-right-button
colorSolarizedDarkPrimaryButton()
.folderItem-right-confirmButton
colorSolarizedDarkPrimaryButton()
.folderItem-right-dangerButton
colorSolarizedDarkPrimaryButton()

View File

@@ -32,6 +32,7 @@ class HotkeyTab extends React.Component {
message: err.message != null ? err.message : 'Error occurs!' message: err.message != null ? err.message : 'Error occurs!'
}}) }})
} }
this.oldHotkey = this.state.config.hotkey
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
} }
@@ -53,6 +54,7 @@ class HotkeyTab extends React.Component {
config: newConfig config: newConfig
}) })
this.clearMessage() this.clearMessage()
this.props.haveToSave()
} }
handleHintToggleButtonClick (e) { handleHintToggleButtonClick (e) {
@@ -70,6 +72,15 @@ class HotkeyTab extends React.Component {
this.setState({ this.setState({
config config
}) })
if (_.isEqual(this.oldHotkey, config.hotkey)) {
this.props.haveToSave()
} else {
this.props.haveToSave({
tab: 'Hotkey',
type: 'warning',
message: 'You have to save!'
})
}
} }
clearMessage () { clearMessage () {
@@ -161,7 +172,8 @@ class HotkeyTab extends React.Component {
} }
HotkeyTab.propTypes = { HotkeyTab.propTypes = {
dispatch: PropTypes.func dispatch: PropTypes.func,
haveToSave: PropTypes.func
} }
export default CSSModules(HotkeyTab, styles) export default CSSModules(HotkeyTab, styles)

View File

@@ -60,3 +60,11 @@
body[data-theme="dark"] body[data-theme="dark"]
.root .root
color alpha($tab--dark-text-color, 80%) color alpha($tab--dark-text-color, 80%)
body[data-theme="solarized-dark"]
.root
color $ui-solarized-dark-text-color
.list
a
color $ui-solarized-dark-active-color

View File

@@ -42,6 +42,8 @@ top-bar--height = 50px
background-color transparent background-color transparent
color $ui-text-color color $ui-text-color
font-size 16px font-size 16px
.saving--warning
haveToSave()
.nav-button--active .nav-button--active
@extend .nav-button @extend .nav-button
@@ -49,6 +51,8 @@ top-bar--height = 50px
background-color $ui-button--active-backgroundColor background-color $ui-button--active-backgroundColor
&:hover &:hover
color $ui-text-color color $ui-text-color
.saving--warning
haveToSave()
.nav-button-icon .nav-button-icon
display block display block
@@ -86,3 +90,29 @@ body[data-theme="dark"]
background-color $dark-primary-button-background--active background-color $dark-primary-button-background--active
&:hover &:hover
color white color white
body[data-theme="solarized-dark"]
.root
background-color transparent
.top-bar
background-color transparent
border-color $ui-solarized-dark-borderColor
p
color $ui-solarized-dark-text-color
.nav
background-color transparent
border-color $ui-solarized-dark-borderColor
.nav-button
background-color transparent
color $ui-solarized-dark-text-color
&:hover
color $ui-solarized-dark-text-color
.nav-button--active
@extend .nav-button
color $ui-solarized-dark-button--active-color
background-color $ui-solarized-dark-button--active-backgroundColor
&:hover
color white

View File

@@ -168,9 +168,9 @@ class StoragesTab extends React.Component {
</select> </select>
<div styleName='addStorage-body-section-type-description'> <div styleName='addStorage-body-section-type-description'>
3rd party cloud integration: 3rd party cloud integration:
<a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing' <a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
onClick={(e) => this.handleLinkClick(e)} onClick={(e) => this.handleLinkClick(e)}
>Cloud-Syncing</a> >Cloud-Syncing-and-Backup</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -158,3 +158,44 @@ body[data-theme="dark"]
.addStorage-body-control-cancelButton .addStorage-body-control-cancelButton
colorDarkDefaultButton() colorDarkDefaultButton()
border-color $ui-dark-borderColor border-color $ui-dark-borderColor
body[data-theme="solarized-dark"]
.root
color $ui-solarized-dark-text-color
.folderList-item
border-bottom $ui-solarized-dark-borderColor
.folderList-empty
color $ui-solarized-dark-text-color
.list-empty
color $ui-solarized-dark-text-color
.list-control-addStorageButton
border-color $ui-solarized-dark-button-backgroundColor
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color
.addStorage-header
color $ui-solarized-dark-text-color
border-color $ui-solarized-dark-borderColor
.addStorage-body-section-name-input
border-color $$ui-solarized-dark-borderColor
.addStorage-body-section-type-description
color $ui-solarized-dark-text-color
.addStorage-body-section-path-button
colorPrimaryButton()
.addStorage-body-control
border-color $ui-solarized-dark-borderColor
.addStorage-body-control-createButton
colorDarkPrimaryButton()
.addStorage-body-control-cancelButton
colorDarkDefaultButton()
border-color $ui-solarized-dark-borderColor

View File

@@ -20,3 +20,8 @@ $tab--dark-text-color = #E5E5E5
body[data-theme="dark"] body[data-theme="dark"]
.header .header
color $tab--dark-text-color color $tab--dark-text-color
haveToSave()
color #FFA500
font-size 10px
margin-top 3px

View File

@@ -7,11 +7,11 @@ import store from 'browser/main/store'
import consts from 'browser/lib/consts' import consts from 'browser/lib/consts'
import ReactCodeMirror from 'react-codemirror' import ReactCodeMirror from 'react-codemirror'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import _ from 'lodash'
const OSX = global.process.platform === 'darwin' const OSX = global.process.platform === 'darwin'
import _ from 'lodash'
const electron = require('electron') const electron = require('electron')
const ipc = electron.ipcRenderer const ipc = electron.ipcRenderer
@@ -62,6 +62,7 @@ class UiTab extends React.Component {
ui: { ui: {
theme: this.refs.uiTheme.value, theme: this.refs.uiTheme.value,
showCopyNotification: this.refs.showCopyNotification.checked, showCopyNotification: this.refs.showCopyNotification.checked,
confirmDeletion: this.refs.confirmDeletion.checked,
disableDirectWrite: this.refs.uiD2w != null disableDirectWrite: this.refs.uiD2w != null
? this.refs.uiD2w.checked ? this.refs.uiD2w.checked
: false : false
@@ -73,13 +74,18 @@ class UiTab extends React.Component {
indentType: this.refs.editorIndentType.value, indentType: this.refs.editorIndentType.value,
indentSize: this.refs.editorIndentSize.value, indentSize: this.refs.editorIndentSize.value,
switchPreview: this.refs.editorSwitchPreview.value, switchPreview: this.refs.editorSwitchPreview.value,
keyMap: this.refs.editorKeyMap.value keyMap: this.refs.editorKeyMap.value,
scrollPastEnd: this.refs.scrollPastEnd.checked
}, },
preview: { preview: {
fontSize: this.refs.previewFontSize.value, fontSize: this.refs.previewFontSize.value,
fontFamily: this.refs.previewFontFamily.value, fontFamily: this.refs.previewFontFamily.value,
codeBlockTheme: this.refs.previewCodeBlockTheme.value, codeBlockTheme: this.refs.previewCodeBlockTheme.value,
lineNumber: this.refs.previewLineNumber.checked lineNumber: this.refs.previewLineNumber.checked,
latexInlineOpen: this.refs.previewLatexInlineOpen.value,
latexInlineClose: this.refs.previewLatexInlineClose.value,
latexBlockOpen: this.refs.previewLatexBlockOpen.value,
latexBlockClose: this.refs.previewLatexBlockClose.value
} }
} }
@@ -88,8 +94,19 @@ class UiTab extends React.Component {
if (newCodemirrorTheme !== codemirrorTheme) { if (newCodemirrorTheme !== codemirrorTheme) {
checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`) checkHighLight.setAttribute('href', `../node_modules/codemirror/theme/${newCodemirrorTheme.split(' ')[0]}.css`)
} }
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme }, () => {
this.setState({ config: newConfig, codemirrorTheme: newCodemirrorTheme }) const {ui, editor, preview} = this.props.config
this.currentConfig = {ui, editor, preview}
if (_.isEqual(this.currentConfig, this.state.config)) {
this.props.haveToSave()
} else {
this.props.haveToSave({
tab: 'UI',
type: 'warning',
message: 'You have to save!'
})
}
})
} }
handleSaveUIClick (e) { handleSaveUIClick (e) {
@@ -106,6 +123,7 @@ class UiTab extends React.Component {
config: newConfig config: newConfig
}) })
this.clearMessage() this.clearMessage()
this.props.haveToSave()
} }
clearMessage () { clearMessage () {
@@ -141,6 +159,7 @@ class UiTab extends React.Component {
> >
<option value='default'>Default</option> <option value='default'>Default</option>
<option value='white'>White</option> <option value='white'>White</option>
<option value='solarized-dark'>Solarized Dark</option>
<option value='dark'>Dark</option> <option value='dark'>Dark</option>
</select> </select>
</div> </div>
@@ -155,6 +174,16 @@ class UiTab extends React.Component {
Show &quot;Saved to Clipboard&quot; notification when copying Show &quot;Saved to Clipboard&quot; notification when copying
</label> </label>
</div> </div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.confirmDeletion}
ref='confirmDeletion'
type='checkbox'
/>&nbsp;
Show a confirmation dialog when deleting notes
</label>
</div>
{ {
global.process.platform === 'win32' global.process.platform === 'win32'
? <div styleName='group-checkBoxSection'> ? <div styleName='group-checkBoxSection'>
@@ -164,7 +193,7 @@ class UiTab extends React.Component {
refs='uiD2w' refs='uiD2w'
disabled={OSX} disabled={OSX}
type='checkbox' type='checkbox'
/> />&nbsp;
Disable Direct Write(It will be applied after restarting) Disable Direct Write(It will be applied after restarting)
</label> </label>
</div> </div>
@@ -274,6 +303,17 @@ class UiTab extends React.Component {
</div> </div>
</div> </div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.editor.scrollPastEnd}
ref='scrollPastEnd'
type='checkbox'
/>&nbsp;
Allow editor to scroll past the last line
</label>
</div>
<div styleName='group-header2'>Preview</div> <div styleName='group-header2'>Preview</div>
<div styleName='group-section'> <div styleName='group-section'>
<div styleName='group-section-label'> <div styleName='group-section-label'>
@@ -326,6 +366,58 @@ class UiTab extends React.Component {
Show line numbers for preview code blocks Show line numbers for preview code blocks
</label> </label>
</div> </div>
<div styleName='group-section'>
<div styleName='group-section-label'>
LaTeX Inline Open Delimiter
</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
ref='previewLatexInlineOpen'
value={config.preview.latexInlineOpen}
onChange={(e) => this.handleUIChange(e)}
type='text'
/>
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
LaTeX Inline Close Delimiter
</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
ref='previewLatexInlineClose'
value={config.preview.latexInlineClose}
onChange={(e) => this.handleUIChange(e)}
type='text'
/>
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
LaTeX Block Open Delimiter
</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
ref='previewLatexBlockOpen'
value={config.preview.latexBlockOpen}
onChange={(e) => this.handleUIChange(e)}
type='text'
/>
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
LaTeX Block Close Delimiter
</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
ref='previewLatexBlockClose'
value={config.preview.latexBlockClose}
onChange={(e) => this.handleUIChange(e)}
type='text'
/>
</div>
</div>
<div styleName='group-control'> <div styleName='group-control'>
<button styleName='group-control-rightButton' <button styleName='group-control-rightButton'
@@ -343,7 +435,8 @@ UiTab.propTypes = {
user: PropTypes.shape({ user: PropTypes.shape({
name: PropTypes.string name: PropTypes.string
}), }),
dispatch: PropTypes.func dispatch: PropTypes.func,
haveToSave: PropTypes.func
} }
export default CSSModules(UiTab, styles) export default CSSModules(UiTab, styles)

View File

@@ -17,7 +17,9 @@ class Preferences extends React.Component {
super(props) super(props)
this.state = { this.state = {
currentTab: 'STORAGES' currentTab: 'STORAGES',
UIAlert: '',
HotkeyAlert: ''
} }
} }
@@ -58,6 +60,7 @@ class Preferences extends React.Component {
<HotkeyTab <HotkeyTab
dispatch={dispatch} dispatch={dispatch}
config={config} config={config}
haveToSave={alert => this.setState({HotkeyAlert: alert})}
/> />
) )
case 'UI': case 'UI':
@@ -65,6 +68,7 @@ class Preferences extends React.Component {
<UiTab <UiTab
dispatch={dispatch} dispatch={dispatch}
config={config} config={config}
haveToSave={alert => this.setState({UIAlert: alert})}
/> />
) )
case 'CROWDFUNDING': case 'CROWDFUNDING':
@@ -94,19 +98,26 @@ class Preferences extends React.Component {
return node.getBoundingClientRect() return node.getBoundingClientRect()
} }
haveToSaveNotif (type, message) {
return (
<p styleName={`saving--${type}`}>{message}</p>
)
}
render () { render () {
const content = this.renderContent() const content = this.renderContent()
const tabs = [ const tabs = [
{target: 'STORAGES', label: 'Storages'}, {target: 'STORAGES', label: 'Storages'},
{target: 'HOTKEY', label: 'Hotkey'}, {target: 'HOTKEY', label: 'Hotkey', Hotkey: this.state.HotkeyAlert},
{target: 'UI', label: 'UI'}, {target: 'UI', label: 'UI', UI: this.state.UIAlert},
{target: 'INFO', label: 'Community / Info'}, {target: 'INFO', label: 'Community / Info'},
{target: 'CROWDFUNDING', label: 'Crowdfunding'} {target: 'CROWDFUNDING', label: 'Crowdfunding'}
] ]
const navButtons = tabs.map((tab) => { const navButtons = tabs.map((tab) => {
const isActive = this.state.currentTab === tab.target const isActive = this.state.currentTab === tab.target
const isUiHotkeyTab = _.isObject(tab[tab.label]) && tab.label === tab[tab.label].tab
return ( return (
<button styleName={isActive <button styleName={isActive
? 'nav-button--active' ? 'nav-button--active'
@@ -118,6 +129,7 @@ class Preferences extends React.Component {
<span styleName='nav-button-label'> <span styleName='nav-button-label'>
{tab.label} {tab.label}
</span> </span>
{isUiHotkeyTab ? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message) : null}
</button> </button>
) )
}) })

View File

@@ -87,8 +87,13 @@ function data (state = defaultDataMap(), action) {
state.trashedSet = new Set(state.trashedSet) state.trashedSet = new Set(state.trashedSet)
if (note.isTrashed) { if (note.isTrashed) {
state.trashedSet.add(uniqueKey) state.trashedSet.add(uniqueKey)
state.starredSet.delete(uniqueKey)
} else { } else {
state.trashedSet.delete(uniqueKey) state.trashedSet.delete(uniqueKey)
if (note.isStarred) {
state.starredSet.add(uniqueKey)
}
} }
} }
@@ -349,6 +354,13 @@ function data (state = defaultDataMap(), action) {
state.storageMap = new Map(state.storageMap) state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage) state.storageMap.set(action.storage.key, action.storage)
return state return state
case 'EXPORT_FOLDER':
{
state = Object.assign({}, state)
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
}
return state
case 'DELETE_FOLDER': case 'DELETE_FOLDER':
{ {
state = Object.assign({}, state) state = Object.assign({}, state)

View File

@@ -46,6 +46,7 @@ tooltip()
// UI Input // UI Input
$ui-input--focus-borderColor = #369DCD $ui-input--focus-borderColor = #369DCD
$ui-input--disabled-backgroundColor = #DDD $ui-input--disabled-backgroundColor = #DDD
$ui-input--create-folder-modal = #C9C9C9
// Parts // Parts
$ui-favorite-star-button-color = #FFC216 $ui-favorite-star-button-color = #FFC216
@@ -106,6 +107,18 @@ colorDarkPrimaryButton()
&:active:hover &:active:hover
background-color $dark-primary-button-background--active background-color $dark-primary-button-background--active
colorSolarizedDarkPrimaryButton()
color $ui-solarized-dark-text-color
background-color $ui-solarized-dark-button-backgroundColor
border none
&:hover
background-color $dark-primary-button-background--hover
&:active
&:active:hover
background-color $dark-primary-button-background--active
// Danger button(Brand color) // Danger button(Brand color)
$danger-button-background = #c9302c $danger-button-background = #c9302c
$danger-button-background--hover = darken(#c9302c, 5%) $danger-button-background--hover = darken(#c9302c, 5%)
@@ -174,20 +187,20 @@ modal()
overflow hidden overflow hidden
border-radius $modal-border-radius border-radius $modal-border-radius
topBarButtonLight() topBarButtonRight()
position absolute position absolute
width 34px width 34px
height 34px height 34px
border-radius 17px border-radius 17px
font-size 14px font-size 14px
border none border none
color alpha($ui-button-color, 0.4) color alpha($ui-button-color, 0.2)
fill $ui-button-color fill $ui-button-color
background-color transparent background-color transparent
&:active &:active
border-color $ui-button--active-backgroundColor border-color $ui-button--active-backgroundColor
&:hover &:hover
transform scale(1.1) // transform scale(1.1)
transition 0.4s transition 0.4s
color $ui-button-color color $ui-button-color
.control-lockButton-tooltip .control-lockButton-tooltip
@@ -223,10 +236,11 @@ $ui-button--focus-borderColor = lighten(#369DCD, 25%)
/******* Dark theme ********/ /******* Dark theme ********/
$ui-dark-active-color = #3A404C $ui-dark-active-color = #3A404C
$ui-dark-borderColor = lighten(#21252B, 20%) $ui-dark-borderColor = #444444
$ui-dark-backgroundColor = #1E2124 $ui-dark-backgroundColor = #2C3033
$ui-dark-noteList-backgroundColor = #282C30 $ui-dark-noteList-backgroundColor = #2C3033
$ui-dark-noteDetail-backgroundColor = #2D3033 $ui-dark-noteDetail-backgroundColor = #2C3033
$ui-dark-tag-backgroundColor = #3A404C $ui-dark-tag-backgroundColor = #3A404C
$dark-background-color = lighten($ui-dark-backgroundColor, 10%) $dark-background-color = lighten($ui-dark-backgroundColor, 10%)
$ui-dark-text-color = #DDDDDD $ui-dark-text-color = #DDDDDD
@@ -249,6 +263,7 @@ colorDarkDefaultButton()
&:active:hover &:active:hover
background-color $ui-dark-button--active-backgroundColor background-color $ui-dark-button--active-backgroundColor
$dark-danger-button-background = #c9302c $dark-danger-button-background = #c9302c
$dark-danger-button-background--hover = darken(#c9302c, 5%) $dark-danger-button-background--hover = darken(#c9302c, 5%)
$dark-danger-button-background--active = darken(#c9302c, 10%) $dark-danger-button-background--active = darken(#c9302c, 10%)
@@ -307,3 +322,30 @@ modalDark()
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
overflow hidden overflow hidden
border-radius $modal-border-radius border-radius $modal-border-radius
/******* Solarized Dark theme ********/
$ui-solarized-dark-backgroundColor = #073642
$ui-solarized-dark-noteList-backgroundColor = #073642
$ui-solarized-dark-noteDetail-backgroundColor = #073642
$ui-solarized-dark-text-color = #93a1a1
$ui-solarized-dark-active-color = #2aa198
$ui-solarized-dark-borderColor = #586e75
$ui-solarized-dark-tag-backgroundColor = #002b36
$ui-solarized-dark-button-backgroundColor = #002b36
$ui-solarized-dark-button--active-color = #93a1a1
$ui-solarized-dark-button--active-backgroundColor = #073642
$ui-solarized-dark-button--hover-backgroundColor = lighten($ui-dark-backgroundColor, 10%)
$ui-solarized-dark-button--focus-borderColor = lighten(#369DCD, 25%)
modalSolarizedDark()
position relative
z-index $modal-z-index
width 100%
background-color $ui-solarized-dark-backgroundColor
overflow hidden
border-radius $modal-border-radius

View File

@@ -1,113 +0,0 @@
@import '../vars'
@import '../mixins/*'
global-reset()
@import '../theme/*'
DEFAULT_FONTS = 'Lato', helvetica, arial, sans-serif
html, body
width 100%
height 100%
overflow hidden
body
font-family DEFAULT_FONTS
color textColor
font-size fontSize
font-weight 400
body[data-modal="open"]
#content *
overflow hidden !important
button, input, select, textarea
font-family DEFAULT_FONTS
div, span, a, button, input, textarea
box-sizing border-box
a
color brandColor
&:hover
color lighten(brandColor, 5%)
&:visited
color brandColor
hr
border-top none
border-bottom solid 1px borderColor
margin 15px 0
button
font-weight 400
cursor pointer
&:focus, &.focus
outline none
.noSelect
noSelect()
.text-center
text-align center
.form-group
margin-bottom 15px
&>label
display block
margin-bottom 5px
.block-input, .inline-input
border solid 1px borderColor
padding 0 10px
font-size 1em
height 33px
border-radius 5px
box-sizing border-box
&:focus, &.focus
border solid 1px brandBorderColor
outline none
&.circleInput
border-radius 16.5px
.block-input
display block
width 100%
.inline-input
display inline-block
margin-right 5px
.relative
position relative
textarea.block-input
resize vertical
height 125px
border-radius 5px
padding 5px 10px
#content
fullsize()
modalZIndex= 1000
modalBackColor = transparentify(black, 65%)
.ModalBase
fixed top left bottom right
z-index modalZIndex
&.hide
display none
.modalBack
absolute top left bottom right
background-color modalBackColor
z-index modalZIndex + 1
.modal
position relative
width 650px
margin 50px auto 0
z-index modalZIndex + 2
background-color white
padding 15px
color #666666
border-radius 5px

View File

@@ -1,5 +1,5 @@
# Build # Build
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), and [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md). This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## Environments ## Environments
* npm: 4.x * npm: 4.x

87
docs/de/build.md Normal file
View File

@@ -0,0 +1,87 @@
# Build
Diese Seite ist auch verfügbar in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## Umgebungen
* npm: 4.x
* node: 7.x
Du solltest `npm v4.x` benutzen weil `$ grunt pre-build` scheitert mit Version `v5.x`.
## Entwicklung
Wir verwenden Webpack HMR für die Entwicklung von Boostnote.
Durch Ausführen der folgenden Befehle, im root Verzeichnis des Projektes, wird Boostnote mit der Default Konfiguration gestartet.
Installiere die nötigen Pakete unter Verwendung von yarn.
```
$ yarn
```
Bauen und Ausführen.
```
$ yarn run dev-start
```
Dieser Befehl startet `yarn run webpack` und `yarn run hot` parallel. Es hat den selben Effekt wie beide Befehle separat in zwei Terminals zu starten.
Das `webpack` überprüft den Code auf Änderungen und wendet diese dann automatisch an.
Wenn folgender Fehler passiert: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, bitte Boostnote neu starten.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Notiz
> Es gibt einige Fälle bei denen die App manuell zu refreshen ist.
> 1. Wenn eine "constructor method" einer Komponente manuell editiert wird.
> 2. Wenn eine neue CSS Klasse ergänzt wird (ähnlich wie 1: die CSS Klasse wird von jeder Komponenete neu geschrieben. Dieser Prozess passiert in der "Constructor method".)
## Deploy
Wir verwenden Grunt um das Deployment zu automatisieren.
Du kannst das Programm unter Verwendung von `grunt` bauen. Jedoch empfehlen wir das nicht denn der default task beinhaltet codesign und authenticode.
Deshalb haben wir ein separates Script vorbereitet welches eine ausführbare Datei erstellt.
Dieser build funktioniert nicht mit npm v5.3.0. Deshalb musst du für den Build die Version v5.2.0 verwenden.
```
grunt pre-build
```
Du findest die ausführbare Datein in dem Verzeichnis `dist`. Beachte, der auto updater funktioniert nicht da die app nicht signiert ist.
Wenn du es für notwendig erachtest, kannst du codesign or authenticode mit dieser ausführbaren Datei verwenden.
## Erstelle eigene Distributions Pakete (deb, rpm)
Distributions Pakete können mittels `grunt build` auf Linux Plattformen (e.g. Ubuntu, Fedora) erstellt werden.
> Beachte: Du kannst bei `.deb` and `.rpm` in der selben Umgebung erstellen.
Nach der Installation der supporteten Version von `node` and `npm`, installiere auch build dependency packages.
Ubuntu/Debian:
```
$ sudo apt-get install -y rpm fakeroot
```
Fedora:
```
$ sudo dnf install -y dpkg dpkg-dev rpm-build fakeroot
```
Dann führe `grunt build` aus.
```
$ grunt build
```
Du findest nun die `.deb` undd `.rpm` Pakete in dem `dist` Ordner.
---
Special thanks: Translated by [gino909](https://github.com/gino909)

25
docs/de/debug.md Normal file
View File

@@ -0,0 +1,25 @@
# How to debug Boostnote (Electron app)
Diese Seite ist auch verfügbar 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), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md).
Boostnote is eine Electron app, somit basiert sie auf Chromium; Entwickler können die `Developer Tools` verwenden, wie Google Chrome.
Du kannst die `Developer Tools` so einschalten:
![how_to_toggle_devTools](https://cloud.githubusercontent.com/assets/11307908/24343585/162187e2-127c-11e7-9c01-23578db03ecf.png)
Die `Developer Tools` schauen dann ungefähr so aus:
![Developer_Tools](https://cloud.githubusercontent.com/assets/11307908/24343545/eff9f3a6-127b-11e7-94cf-cb67bfda634a.png)
Wenn Fehler vorkommen, werden die Fehlermeldungen in der `console` ausgegeben.
## Debugging
Zum Beispiel kannst du mit dem `debugger` Haltepunkte im Code setzen wie hier veranschaulicht:
![debugger](https://cloud.githubusercontent.com/assets/11307908/24343879/9459efea-127d-11e7-9943-f60bf7f66d4a.png)
Das ist ledigtlich ein Beispiel, du kannst die Art von Debugging verwenden die für dich am besten ist.
## Referenz
* [Official document of Google Chrome about debugging](https://developer.chrome.com/devtools)
---
Special thanks: Translated by [gino909](https://github.com/gino909)

View File

@@ -1,5 +1,5 @@
# How to debug Boostnote (Electron app) # How to debug Boostnote (Electron app)
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), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), and [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/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), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md).
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome. Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.

View File

@@ -28,12 +28,14 @@
<script src="../node_modules/codemirror/lib/codemirror.js"></script> <script src="../node_modules/codemirror/lib/codemirror.js"></script>
<script src="../node_modules/codemirror/mode/meta.js"></script> <script src="../node_modules/codemirror/mode/meta.js"></script>
<script src="../node_modules/codemirror-mode-elixir/dist/elixir.js"></script>
<script src="../node_modules/codemirror/addon/mode/overlay.js"></script> <script src="../node_modules/codemirror/addon/mode/overlay.js"></script>
<script src="../node_modules/codemirror/addon/mode/loadmode.js"></script> <script src="../node_modules/codemirror/addon/mode/loadmode.js"></script>
<script src="../node_modules/codemirror/keymap/sublime.js"></script> <script src="../node_modules/codemirror/keymap/sublime.js"></script>
<script src="../node_modules/codemirror/keymap/vim.js"></script> <script src="../node_modules/codemirror/keymap/vim.js"></script>
<script src="../node_modules/codemirror/keymap/emacs.js"></script> <script src="../node_modules/codemirror/keymap/emacs.js"></script>
<script src="../node_modules/codemirror/addon/runmode/runmode.js"></script> <script src="../node_modules/codemirror/addon/runmode/runmode.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/raphael/raphael.min.js"></script> <script src="../node_modules/raphael/raphael.min.js"></script>
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script> <script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>

View File

@@ -65,14 +65,6 @@ updater.autoUpdater.on('error', (err) => {
console.log(err) console.log(err)
}) })
ipc.on('update-check', function (event, msg) {
if (isUpdateReady) {
mainWindow.webContents.send('update-ready', 'Update available!')
} else {
checkUpdate()
}
})
ipc.on('update-app-confirm', function (event, msg) { ipc.on('update-app-confirm', function (event, msg) {
if (isUpdateReady) { if (isUpdateReady) {
mainWindow.removeAllListeners() mainWindow.removeAllListeners()
@@ -102,12 +94,11 @@ app.on('ready', function () {
Menu.setApplicationMenu(menu) Menu.setApplicationMenu(menu)
break break
case 'win32': case 'win32':
/* eslint-disable */ require('./finder-window')
finderWindow = require('./finder-window')
/* eslint-disable */
mainWindow.setMenu(menu) mainWindow.setMenu(menu)
break break
case 'linux': case 'linux':
require('./finder-window')
Menu.setApplicationMenu(menu) Menu.setApplicationMenu(menu)
mainWindow.setMenu(menu) mainWindow.setMenu(menu)
} }
@@ -115,9 +106,20 @@ app.on('ready', function () {
// Check update every hour // Check update every hour
setInterval(function () { setInterval(function () {
checkUpdate() checkUpdate()
}, 1000 * 60 * 60) }, 1000 * 60 * 60 * 24)
checkUpdate() // Check update after 10 secs to prevent file locking of Windows
setTimeout(() => {
checkUpdate()
ipc.on('update-check', function (event, msg) {
if (isUpdateReady) {
mainWindow.webContents.send('update-ready', 'Update available!')
} else {
checkUpdate()
}
})
}, 10000)
ipcServer = require('./ipcServer') ipcServer = require('./ipcServer')
ipcServer.server.start() ipcServer.server.start()
}) })

View File

@@ -20,6 +20,7 @@ const boost = macOS
}, },
{ {
label: 'Preferences', label: 'Preferences',
accelerator: 'Command+,',
click () { click () {
mainWindow.webContents.send('side:preferences') mainWindow.webContents.send('side:preferences')
} }
@@ -56,6 +57,7 @@ const boost = macOS
submenu: [ submenu: [
{ {
label: 'Preferences', label: 'Preferences',
accelerator: 'Control+,',
click () { click () {
mainWindow.webContents.send('side:preferences') mainWindow.webContents.send('side:preferences')
} }
@@ -106,6 +108,13 @@ const file = {
mainWindow.webContents.send('list:isMarkdownNote') mainWindow.webContents.send('list:isMarkdownNote')
mainWindow.webContents.send('export:save-md') mainWindow.webContents.send('export:save-md')
} }
},
{
label: 'HTML (.html)',
click () {
mainWindow.webContents.send('list:isMarkdownNote')
mainWindow.webContents.send('export:save-html')
}
} }
] ]
}, },
@@ -152,6 +161,7 @@ if (LINUX) {
type: 'separator' type: 'separator'
}, { }, {
label: 'Preferences', label: 'Preferences',
accelerator: 'Control+,',
click () { click () {
mainWindow.webContents.send('side:preferences') mainWindow.webContents.send('side:preferences')
} }

View File

@@ -69,6 +69,7 @@
<script src="../node_modules/codemirror/lib/codemirror.js"></script> <script src="../node_modules/codemirror/lib/codemirror.js"></script>
<script src="../node_modules/codemirror/mode/meta.js"></script> <script src="../node_modules/codemirror/mode/meta.js"></script>
<script src="../node_modules/codemirror-mode-elixir/dist/elixir.js"></script>
<script src="../node_modules/codemirror/addon/mode/overlay.js"></script> <script src="../node_modules/codemirror/addon/mode/overlay.js"></script>
<script src="../node_modules/codemirror/addon/mode/loadmode.js"></script> <script src="../node_modules/codemirror/addon/mode/loadmode.js"></script>
<script src="../node_modules/codemirror/addon/mode/simple.js"></script> <script src="../node_modules/codemirror/addon/mode/simple.js"></script>
@@ -79,9 +80,12 @@
<script src="../node_modules/codemirror/addon/edit/continuelist.js"></script> <script src="../node_modules/codemirror/addon/edit/continuelist.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/codemirror/addon/search/search.js"></script> <script src="../node_modules/codemirror/addon/search/search.js"></script>
<script src="../node_modules/codemirror/addon/search/searchcursor.js"></script> <script src="../node_modules/codemirror/addon/search/searchcursor.js"></script>
<script src="../node_modules/codemirror/addon/scroll/annotatescrollbar.js"></script> <script src="../node_modules/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="../node_modules/codemirror/addon/scroll/scrollpastend.js"></script>
<script src="../node_modules/codemirror/addon/search/matchesonscrollbar.js"></script> <script src="../node_modules/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="../node_modules/codemirror/addon/search/jump-to-line.js"></script> <script src="../node_modules/codemirror/addon/search/jump-to-line.js"></script>
<script src="../node_modules/codemirror/addon/dialog/dialog.js"></script> <script src="../node_modules/codemirror/addon/dialog/dialog.js"></script>

View File

@@ -1,7 +1,7 @@
{ {
"name": "boost", "name": "boost",
"productName": "Boostnote", "productName": "Boostnote",
"version": "0.8.18", "version": "0.8.20",
"main": "index.js", "main": "index.js",
"description": "Boostnote", "description": "Boostnote",
"license": "GPL-3.0", "license": "GPL-3.0",
@@ -16,7 +16,7 @@
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\"" "dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
}, },
"config": { "config": {
"electron-version": "1.6.15" "electron-version": "1.7.10"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -53,6 +53,7 @@
"aws-sdk": "^2.48.0", "aws-sdk": "^2.48.0",
"aws-sdk-mobile-analytics": "^0.9.2", "aws-sdk-mobile-analytics": "^0.9.2",
"codemirror": "^5.19.0", "codemirror": "^5.19.0",
"codemirror-mode-elixir": "^1.1.1",
"electron-config": "^0.2.1", "electron-config": "^0.2.1",
"electron-gh-releases": "^2.0.2", "electron-gh-releases": "^2.0.2",
"flowchart.js": "^1.6.5", "flowchart.js": "^1.6.5",
@@ -102,15 +103,16 @@
"css-loader": "^0.19.0", "css-loader": "^0.19.0",
"devtron": "^1.1.0", "devtron": "^1.1.0",
"dom-storage": "^2.0.2", "dom-storage": "^2.0.2",
"electron": "1.7.10",
"electron-packager": "^6.0.0", "electron-packager": "^6.0.0",
"electron": "^1.6.15",
"eslint": "^3.13.1", "eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1", "eslint-config-standard": "^6.2.1",
"eslint-config-standard-jsx": "^3.2.0", "eslint-config-standard-jsx": "^3.2.0",
"eslint-plugin-react": "^7.2.0", "eslint-plugin-react": "^7.2.0",
"eslint-plugin-standard": "^3.0.1",
"faker": "^3.1.0", "faker": "^3.1.0",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"grunt-electron-installer": "^1.2.0", "grunt-electron-installer": "2.1.0",
"history": "^1.17.0", "history": "^1.17.0",
"jsdom": "^9.4.2", "jsdom": "^9.4.2",
"json-loader": "^0.5.4", "json-loader": "^0.5.4",

View File

@@ -1,6 +1,4 @@
New:zap: :mega: Open sourcing our [Android and iOS apps](https://github.com/BoostIO/Boostnote-mobile)!
Open sourcing our [Android and iOS apps](https://github.com/BoostIO/Boostnote-mobile)!
![Boostnote app screenshot](./resources/repository/top.png) ![Boostnote app screenshot](./resources/repository/top.png)
@@ -12,7 +10,6 @@ Open sourcing our [Android and iOS apps](https://github.com/BoostIO/Boostnote-mo
## Authors & Maintainers ## Authors & Maintainers
- [Rokt33r](https://github.com/rokt33r) - [Rokt33r](https://github.com/rokt33r)
- [sota1235](https://github.com/sota1235)
- [Kohei TAKATA](https://github.com/kohei-takata) - [Kohei TAKATA](https://github.com/kohei-takata)
- [Sosuke](https://github.com/sosukesuzuki) - [Sosuke](https://github.com/sosukesuzuki)
- [Kazz](https://github.com/kazup01) - [Kazz](https://github.com/kazup01)
@@ -26,16 +23,20 @@ Thank you to all the people who already contributed to Boostnote!
Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider: Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider:
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio) - [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
## Slack Group ## Community
Let's talk about Boostnote! <br> - [Facebook Group](https://www.facebook.com/groups/boostnote/)
[Join us](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjc2MDM0MDEyODk2LThlZDlhYmYwMjdkMmJjMGM5MGFiMGJmNzk5ZTdhNzFhMmNmMDFlY2M2YTE1MTZkOThiOGZmNTI3YzJiOTBhMTQ) - [Twitter](https://twitter.com/boostnoteapp)
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjkxMzMwODYxMDI1LTgwZmRiODg0NzA5MWRmOTJjNzBjZjAwMmMyZGQ4Y2RkOGE0MDg0YjcyMjA5OGUzMmZhNmFiNTMzOTlkYWNlMTM)
- [Blog](https://medium.com/boostnote)
- [Reddit](https://www.reddit.com/r/Boostnote/)
## More Information
#### More Information
* [Website](https://boostnote.io) * [Website](https://boostnote.io)
* [Subscribe to the Newsletter](https://boostnote.io/#community): Get updates on Boostnote progress. No spam, ever :) * [Subscribe to the Newsletter](https://boostnote.io/#community): Get updates on Boostnote progress. No spam, ever :)
* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md): Development configurations for Boostnote. * [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md): Development configurations for Boostnote.
* Copyright (C) 2017 Maisin&Co. * Copyright (C) 2017 Maisin&Co.
## License #### License
[GPL v3](./LICENSE). [GPL v3](./LICENSE).

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="20px" viewBox="0 0 18 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>icon-code-off</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="Artboard-4" transform="translate(-1317.000000, -294.000000)" stroke="#8A8C8D" stroke-width="2">
<g id="icon-code-off" transform="translate(1318.000000, 295.000000)">
<path d="M0,6 L16,6" id="Shape"></path>
<path d="M0,12 L16,12" id="Shape"></path>
<path d="M6,0 L4,18" id="Shape"></path>
<path d="M12,0 L10,18" id="Shape"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 952 B

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="15px" viewBox="0 0 14 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>icon-code-on</title>
<desc>Created with Sketch.</desc>
<defs>
<filter x="0.0%" y="0.0%" width="100.0%" height="100.0%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowOffsetOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="Artboard-4" transform="translate(-1480.000000, -373.000000)" stroke="#1EC38B" stroke-width="1.43999988">
<g id="Group" filter="url(#filter-1)" transform="translate(1336.000000, 363.000000)">
<g id="icon-code-on" transform="translate(145.000000, 11.657143)">
<path d="M0,4.51020408 L12,4.51020408" id="Shape"></path>
<path d="M0,8.11836735 L12,8.11836735" id="Shape"></path>
<path d="M4.61538462,0 L2.76923077,12.6285714" id="Shape"></path>
<path d="M9.23076923,0 L7.38461538,12.6285714" id="Shape"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="17px" height="19px" viewBox="0 0 17 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-edit-lock</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Artboard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-1443.000000, -336.000000)" stroke-linecap="round" stroke-linejoin="round">
<g id="icon-edit-lock" transform="translate(1444.000000, 337.000000)" stroke="#1EC38B" stroke-width="1.66666667">
<polygon id="Shape" points="9.16666667 0 12.5 3.42857143 3.33333333 12.8571429 0 12.8571429 0 9.42857143"></polygon>
<path d="M0,17.1428571 L15,17.1428571" id="Shape"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 887 B

Some files were not shown because too many files have changed in this diff Show More