Compare commits

...

189 Commits

Author SHA1 Message Date
ammarahm-ed
e9d43f3026 feat(tinymce-plugins): touch input support in collapsibleheaders 2022-03-09 11:35:17 +05:00
thecodrr
57df03e46c chore(tinymce-plugins): bump version to 1.5.14 2022-03-08 14:21:59 +05:00
thecodrr
b673519898 feat(tinymce-plugins): add support for h1 in collapsible headers 2022-03-08 14:21:31 +05:00
thecodrr
5356e9d4ed chore(tinymce-plugins): bump version to 1.5.13 2022-03-07 17:29:51 +05:00
thecodrr
3d1b9de51b fix(tinymce-plugins): do not autofocus on set content 2022-03-07 17:29:31 +05:00
thecodrr
c1741b1924 chore(tinymce-plugins): bump version to 1.5.12 2022-03-04 23:36:54 +05:00
thecodrr
4a17164bd9 fix: minimized state of headings should get saved
(fixes #377)
2022-03-04 23:33:12 +05:00
ammarahm-ed
c26dbefe26 fix: nested checklist items not checked on mobile 2022-02-24 13:29:56 +05:00
thecodrr
f532d6f01b chore(tinymce-plugins): bump version to 1.5.11 2022-02-19 20:27:56 +05:00
thecodrr
351f56dc0d fix(tinymce-plugins): auto check last checklist item
this ensures that if tinymce auto merges two checklists
due to close proximity, the first element of the second list
would get checked instead of the first elemtn of the first list.
2022-02-19 20:27:36 +05:00
thecodrr
feb74ae910 chore(tinymce-plugins): bump version to 1.5.10 2022-02-19 20:22:11 +05:00
thecodrr
4b483d200d feat: allow checking first item via execCommand 2022-02-19 20:21:52 +05:00
Abdullah Atta
5858cae55b feat: open source notesnook crypto module (#329)
* chore: open-source notesnook crypto

* chore(crypto): remove useless webpack config

* chore(crypto): add npmignore file
2022-02-02 10:32:02 +05:00
thecodrr
e7491d1c03 chore(tinymce-plugins): bump version to 1.5.9 2022-01-31 11:52:15 +05:00
thecodrr
e740d56a84 fix(tinymce-plugins): jumpto next p tag on enter press 2022-01-31 11:51:35 +05:00
thecodrr
01c78c654d ci: fix "cd: app/importer: No such file or directory" 2022-01-24 11:15:13 +05:00
thecodrr
db67114a30 chore(importer-web): bump version to 1.1.2 2022-01-24 11:13:11 +05:00
thecodrr
7483286833 chore(importer-web): update @notesnook/importer 2022-01-24 11:12:49 +05:00
thecodrr
9606517f38 ci: deploy importer web app directly 2022-01-24 11:11:01 +05:00
thecodrr
1d86624ce3 test(importer): update snapshots 2022-01-24 11:09:23 +05:00
thecodrr
bdc2af9597 chore(importer): bump version to 1.1.3 2022-01-24 11:07:05 +05:00
thecodrr
41d77b6424 chore(importer): update @notesnook/enex 2022-01-24 11:06:53 +05:00
thecodrr
3bda97b4f5 chore(enex): bump version to 1.0.3 2022-01-24 11:04:58 +05:00
thecodrr
5d5b1e9eac fix(enex): derive md5 hash of att. manually 2022-01-24 11:03:25 +05:00
thecodrr
f46ef8347f chore(tinymce-plugins): @streetwritersco -> @streetwriters 2022-01-22 13:31:40 +05:00
thecodrr
c613e67218 chore(tinymce-plugins): bump version to 1.5.7 2022-01-22 13:27:16 +05:00
thecodrr
a9ff91d51e fix(tinymce-plugins): make inlinecode toggleable 2022-01-22 13:26:45 +05:00
thecodrr
52f51c4087 chore(importer-web): bump version to 1.1.1 2022-01-21 23:54:45 +05:00
thecodrr
f0ec25c296 chore(importer-web): update importer core 2022-01-21 23:54:11 +05:00
thecodrr
d2ae716993 chore(importer): bump version to 1.1.2 2022-01-21 23:53:24 +05:00
thecodrr
8d432d4810 fix(importer): typo in DefaultAppDomain 2022-01-21 23:53:06 +05:00
thecodrr
e2bd1cd1f1 chore(importer-web): bump version to 1.1.0 2022-01-21 23:37:42 +05:00
thecodrr
7286c60961 chore(importer-web): update importer core 2022-01-21 23:25:58 +05:00
thecodrr
8a9cd91d54 chore(importer): bump version 1.1.1 2022-01-21 23:22:03 +05:00
thecodrr
462ae4d8ab fix: move @standardnotes/common & @standardnotes/features to dependencies 2022-01-21 23:21:22 +05:00
thecodrr
45e7d5e46b chore(importer): add Standard Notes to readme 2022-01-21 21:34:51 +05:00
thecodrr
9426e937a5 test(importer): update snapshots 2022-01-21 21:34:31 +05:00
thecodrr
8ec4102395 fix: log errors during unpacking 2022-01-21 21:34:13 +05:00
thecodrr
4832d243da refactor: use snjs types instead of our own 2022-01-21 21:33:11 +05:00
thecodrr
9504f278c3 refactor: move table & codeblock construction logic into domutils 2022-01-21 21:32:44 +05:00
Ammar Ahmed
8cefa1defc feat: add standard notes support in importer (#285)
* add support for standard notes in importer

* rename types

* move editors to constants.ts

* change ContentTypes to enum

* make all properties of SNBackup optional

* add version & backup file check

* refactor buildTableWithRows function

* rename mode to language

* use inverted condition to reduce indent

* refactor table construction html strings
2022-01-20 10:49:29 +05:00
thecodrr
b4e58139e3 ci: do not build before running tests 2022-01-19 17:34:29 +05:00
thecodrr
73f60704dd ci: rename workflows for enex & importer packages 2022-01-19 17:29:51 +05:00
thecodrr
470e3040fc ci: fix syntax errors in workflows 2022-01-19 17:29:15 +05:00
thecodrr
73d9a0f371 ci: add workflows for testing enex & importer packages 2022-01-19 17:27:53 +05:00
thecodrr
7a01898b2b chore(importer-web): update importer core 2022-01-19 17:23:10 +05:00
thecodrr
41f5a4eecf chore(importer): publish v1.0.0 on npm 2022-01-19 17:19:56 +05:00
thecodrr
08744fd0ee test(importer): improve packed payload test 2022-01-19 17:09:43 +05:00
thecodrr
4788060c5a chore(enex): bump version to 1.0.2 2022-01-19 16:44:22 +05:00
thecodrr
7a5e49bcbe chore(enex): use thecodrr/node-html-parser package 2022-01-19 16:43:57 +05:00
thecodrr
536744f74a chore(enex): publish 2022-01-19 16:31:30 +05:00
thecodrr
b1c33ebf28 chore(enex): bump version to 1.0.1 2022-01-19 12:27:19 +05:00
thecodrr
323cd373e5 fix(enex): properly remove newlines from base64 data 2022-01-19 12:26:29 +05:00
thecodrr
6c5cfb1505 docs: fix doc page crash with syntax error 2022-01-19 11:59:55 +05:00
ammarahm-ed
b628e6071e docs: fix output path incorrect in config file 2022-01-17 01:23:20 +05:00
ammarahm-ed
8a2c1c0b2a docs: fix generator output path regex 2022-01-17 01:22:17 +05:00
ammarahm-ed
77734aebba docs: update retype to 1.11.2 2022-01-17 01:09:32 +05:00
ammarahm-ed
31711987c3 docs: remove rich-text-editing route 2022-01-13 11:33:59 +05:00
thecodrr
e193afb97d chore(tinymce-plugins): bump version to 1.5.6 2022-01-10 12:23:02 +05:00
thecodrr
02b8fc4eb5 fix: do not touch data-mce-bogus elements (fixes #279) 2022-01-10 12:22:21 +05:00
thecodrr
fd68f02f60 chore(tinymce-plugins): bump version to 1.5.5 2022-01-05 15:07:06 +05:00
thecodrr
6089c58177 chore(tinymce-plugins): add docs for firstLineBackspaceQuirk 2022-01-04 11:11:07 +05:00
thecodrr
cfdfbb36cb fix(tinymce-plugins): first line not backspace-able (#132) 2022-01-04 11:05:53 +05:00
thecodrr
38791a3760 Merge branch 'main' of https://github.com/streetwriters/notesnook 2022-01-04 10:16:01 +05:00
thecodrr
e1426d4c73 fix(tinymce-plugins): text after cursor is deleted on enter 2022-01-04 10:15:58 +05:00
Ammar Ahmed
71e45c23b5 fix: improve checklist responsiveness on touch devices (#267)
* Update index.js

* fix event.targetTouches can cause error

* bump version of tinymce plugins
2022-01-04 09:56:43 +05:00
thecodrr
673e0287bc fix: include .gif in keep valid extensions (fixes #240) 2021-12-30 14:50:45 +05:00
thecodrr
bda62c761a ci: move build files to public_html before deploy 2021-12-30 10:24:59 +05:00
thecodrr
412b40d64f ci: allow triggering importer action manually 2021-12-30 10:05:03 +05:00
thecodrr
975bc3e64d ci: use turbo to run build 2021-12-30 09:59:22 +05:00
thecodrr
2832af2753 chore: finalize notesnook-import v1.0.0 2021-12-30 09:48:26 +05:00
thecodrr
258e9f0a21 ci: use correct gh action names 2021-12-30 09:35:00 +05:00
thecodrr
8a9de63ebc ci: fix a step cannot have both the uses and run keys 2021-12-30 09:33:49 +05:00
thecodrr
49ec85effd ci: add importer deploy action 2021-12-30 09:30:52 +05:00
thecodrr
87e70b2aef chore(tinymce-plugins): bump version to 1.5.3 2021-12-29 12:41:11 +05:00
thecodrr
c6f5276619 fix(tinymce-plugins): remove :not css selector from filters
:not() css selector is only supported in modern browsers
causing crashes in older browsers during saving.
2021-12-29 12:40:58 +05:00
thecodrr
640f03af97 ci(docs): get docs deploy working again 2021-12-28 13:06:18 +05:00
thecodrr
92c2538fbc chore(tinymce-plugins): bump version to 1.5.2 2021-12-28 12:49:28 +05:00
thecodrr
867edbd878 fix(tinymce-plugins): strip data-mce-active attribute 2021-12-28 12:49:14 +05:00
thecodrr
6e2bcdd832 chore(tinymce-plugins): bump version to 1.5.1 2021-12-28 12:45:23 +05:00
thecodrr
25e12564b6 Merge branch 'main' of https://github.com/streetwriters/notesnook 2021-12-28 12:44:54 +05:00
thecodrr
cf0a12bdb9 fix(tinymce-plugins): fire editor change event on check/uncheck 2021-12-28 12:44:34 +05:00
ammarahm-ed
9dce7c737e docs: add retype.yml 2021-12-25 12:56:13 +05:00
ammarahm-ed
0bdb135b7b docs: add version history docs 2021-12-25 12:45:45 +05:00
thecodrr
d9e3798dd1 chore(tinymce-plugins): bump version to 1.5.0 2021-12-24 12:29:17 +05:00
thecodrr
4d9c108144 refactor(tinymce-plugins): use switch stmnt to handle beforeexeccommand 2021-12-24 12:28:51 +05:00
thecodrr
ba19214307 feat(tinymce-plugins): add bettertable plugin 2021-12-24 12:01:03 +05:00
thecodrr
1aee142b59 chore(tinymce-plugins): bump version to 1.4.15 2021-12-24 07:22:15 +05:00
thecodrr
eedf201a61 fix(tinymce-plugins): unlink command doesn't fire event 2021-12-24 07:21:45 +05:00
thecodrr
b7acb75686 chore(tinymce-plugins): bump version to 1.4.14 2021-12-23 12:41:33 +05:00
thecodrr
ee8924c7c5 fix(tinymce-plugins): send inputType with input event 2021-12-23 12:41:16 +05:00
thecodrr
6461fac76e chore(tinymce-plugins): bump version to 1.4.13 2021-12-23 12:09:01 +05:00
thecodrr
3c31fcbe6e fix(tinymce-plugins): editor is not defined 2021-12-23 12:08:49 +05:00
thecodrr
858c92aad5 chore(tinymce-plugins): bump version to 1.4.12 2021-12-23 12:06:59 +05:00
thecodrr
c03e672623 fix(tinymce-plugins): fire input event on att. add/delete 2021-12-23 12:06:36 +05:00
thecodrr
ae8720d69a chore(tinymce-plugins): bump version to 1.4.11 2021-12-23 10:54:18 +05:00
thecodrr
6db218fc06 fix(tinymce-plugins): focus editor after setting content 2021-12-23 10:53:55 +05:00
thecodrr
77e28d25e3 chore(tinymce-plugins): bump version to 1.4.10 2021-12-20 09:59:06 +05:00
thecodrr
309ca061a2 refactor(tinymce-plugins): tox-checklist -> checklist 2021-12-20 09:57:57 +05:00
thecodrr
5268485715 fix(importer): attachment html generation 2021-12-20 09:53:37 +05:00
thecodrr
ee1517e800 fix(importer): make attachment filename mandatory 2021-12-20 09:52:18 +05:00
thecodrr
5770972e88 chore: initialize turborepo & changesets 2021-12-18 11:07:37 +05:00
thecodrr
dc24e629c5 feat: add importer frontend app 2021-12-18 10:06:35 +05:00
thecodrr
9dd125656b refactor: move importer lib to root folder 2021-12-18 10:06:05 +05:00
thecodrr
3f548e1086 chore: compile @notesnook/enex package 2021-12-18 10:04:36 +05:00
thecodrr
919710c069 refactor: seperate importer app & lib 2021-12-18 10:03:26 +05:00
thecodrr
9b4b28741f feat: initialize importer webapp 2021-12-14 09:33:30 +05:00
thecodrr
7d078e9e40 feat: remove old js importer code 2021-12-14 09:08:32 +05:00
thecodrr
bf194ff7d2 feat: finalize importer backend 2021-12-13 10:24:55 +05:00
thecodrr
2e02b57068 chore: bump tinymce-plugins to 1.4.9 2021-12-10 11:52:58 +05:00
thecodrr
5696de8a24 fix: Uncaught ReferenceError: blobCache is not defined (#149) 2021-12-10 11:06:06 +05:00
thecodrr
39b7057bb7 chore: bump tinymce-plugins version to 1.4.8 2021-12-09 09:19:16 +05:00
thecodrr
78f6d18386 fix: do not remove br element in empty p tags 2021-12-09 09:18:40 +05:00
thecodrr
f1c4d5a78d chore: bump tinymce-plugins to 1.4.7 2021-12-06 09:46:23 +05:00
thecodrr
13ab6ca9f7 enex: add isNotebook property 2021-12-06 09:37:35 +05:00
thecodrr
6920147a17 enex: replace querySelector with findChild helper 2021-12-06 09:37:17 +05:00
thecodrr
1ba1c52165 enex: export TaskStatus enum 2021-12-06 09:36:55 +05:00
thecodrr
b7bc1741d6 enex: getElementsByTagName to querySelectorAll 2021-12-06 09:36:38 +05:00
thecodrr
6b4ca9f2ae enex: improve enml to html conversion 2021-12-06 09:31:29 +05:00
thecodrr
6616e87e1d feat: set & clear contents directly 2021-12-06 09:30:31 +05:00
thecodrr
0eb0e4fceb perf: clone node instead of using DOMParser 2021-12-06 09:30:13 +05:00
thecodrr
481a31ab27 fix: allow elementhandler to return undefined 2021-11-27 09:14:46 +05:00
thecodrr
255cb89523 feat: add enex parser 2021-11-27 09:12:38 +05:00
thecodrr
bda96a7d82 chore: bump version to 1.4.6 2021-11-23 20:38:54 +05:00
thecodrr
8ccc7136e2 fix: sanity check for editor.getBody 2021-11-23 20:38:41 +05:00
thecodrr
468498f087 chore: bump tinymce-plugins to 1.4.5 2021-11-20 13:30:13 +05:00
thecodrr
1a57ef5177 fix: sanitze all elements 2021-11-20 13:28:37 +05:00
thecodrr
e3b428a3fb chore: bump tinymce-plugins to version 1.4.4 2021-11-20 12:27:48 +05:00
thecodrr
65e1ced04c feat: add improved dom filtering logic 2021-11-20 12:26:39 +05:00
thecodrr
95d1f17c40 fix: remove data-mce-selected attribute 2021-11-20 12:06:51 +05:00
thecodrr
1fe3b77ba1 chore: bump tinymce-plugins to 1.4.3 2021-11-19 12:02:00 +05:00
thecodrr
0250a86b12 fix: image is not defined 2021-11-19 12:01:37 +05:00
thecodrr
bf64300c68 chore: bump tinymce-plugins to 1.4.2 2021-11-19 11:56:26 +05:00
thecodrr
6280ba31c3 fix: remove tinymce bogus elements 2021-11-19 11:55:52 +05:00
thecodrr
ad4d3c8889 chore: bump tinymce-plugins to 1.4.1 2021-11-19 11:05:04 +05:00
thecodrr
2a96b9c615 fix: use editor.getBody to support iframe editors 2021-11-19 11:04:47 +05:00
thecodrr
5dcc8b3b12 chore: bump tinymce-plugins to 1.4.0 2021-11-19 10:44:53 +05:00
thecodrr
429c6f0e69 feat: add contenthandler plugin 2021-11-19 10:44:05 +05:00
thecodrr
b25f4f3145 fix: evernote output has unnecessary en-note tag 2021-11-05 09:53:09 +05:00
thecodrr
7d33160817 chore: bump tinymce-plugins version to 1.3.11 2021-11-04 20:38:22 +05:00
thecodrr
a73a1b36c8 test: add e2e tests for codeblock 2021-11-04 20:37:07 +05:00
thecodrr
b9860eb21e chore: bump tinymce-plugins version to 1.3.10 2021-11-04 12:07:37 +05:00
thecodrr
b471e44f04 fix: code block is not toggleable (fixes #68) 2021-11-04 11:06:44 +05:00
thecodrr
79f5b30ce4 chore: bump tinymce-plugins to 1.3.9 2021-11-04 10:21:51 +05:00
thecodrr
f858b6ace3 fix: debounce returns a function; call it 2021-11-04 10:21:34 +05:00
thecodrr
c1a700029f chore: bump tinymce-plugins to 1.3.8 2021-11-04 10:14:16 +05:00
thecodrr
34168716fe fix: refresh highlighting on all keys with 500 debounce 2021-11-04 10:13:53 +05:00
thecodrr
164710b56b chore: remove unnecessary console.log 2021-11-04 10:01:40 +05:00
thecodrr
ec5db3f8ea chore: bump tinymce-plugins to 1.3.7 2021-11-04 10:00:26 +05:00
thecodrr
a9f1d12e37 fix: make codeblock compatible with iframe tinymce 2021-11-04 09:59:50 +05:00
thecodrr
8091d5f906 chore: bump tinymce-plugins to v1.3.6 2021-11-04 09:02:57 +05:00
thecodrr
a240e9cdee docs: update roadmap 2021-11-04 09:01:47 +05:00
thecodrr
d5b8b06981 feat: use highlight.js package to load the hljs core 2021-11-04 09:01:03 +05:00
thecodrr
7820b33bce ci: use a specific retypeapp version 2021-11-04 09:00:29 +05:00
thecodrr
494eda997c chore: bump version to 1.3.5 2021-11-01 09:43:44 +05:00
thecodrr
a7425e7636 fix: tab not working in codeblock 2021-10-30 21:48:24 +05:00
thecodrr
af999ffe8a chore: update tinymce-plugins to v1.3.4 2021-10-30 14:32:31 +05:00
thecodrr
86ffc8c321 fix: do not focus editor on image injection 2021-10-30 14:32:04 +05:00
thecodrr
217de2dd17 fix: make codeblock tab functional again 2021-10-30 14:31:31 +05:00
thecodrr
428abf73da chore: bump tinymce-plugins to v1.3.3 2021-10-22 16:31:00 +05:00
thecodrr
441d081e66 fix: do not load languages if already loaded 2021-10-22 16:30:44 +05:00
thecodrr
72a938e33a chore: bump tinymce-plugins to v1.3.2 2021-10-21 23:57:26 +05:00
thecodrr
c36b6aef35 feat: dynamically load hljs & highlighters 2021-10-21 20:37:53 +05:00
thecodrr
540b6fe8f0 chore: bump version to 1.3.1 2021-10-20 14:03:32 +05:00
thecodrr
1243f76dd1 fix: manually convert datauri to blob 2021-10-20 14:03:10 +05:00
thecodrr
00e751b6ef chore: bump version to 1.3.0 2021-10-20 09:57:57 +05:00
thecodrr
718be83e60 feat: turn off spellcheck for inline-code 2021-10-20 09:57:34 +05:00
thecodrr
d6e199a77e feat: put filename ina seperate span 2021-10-20 09:57:10 +05:00
thecodrr
ec82bf32f8 feat: attach images as blob instead of dataurl 2021-10-18 14:00:58 +05:00
thecodrr
cb1ccc19e5 feat: improve code-block ux 2021-10-17 13:04:27 +05:00
thecodrr
28bd768793 fix: weird glitch in codeblock on tab key press 2021-10-17 01:45:21 +05:00
thecodrr
553938e2ab feat: add blockescape plugin for easy escaping
from block elements
2021-10-16 10:28:05 +05:00
thecodrr
f9895f2749 fix: inline code isn't added without selecting text 2021-10-16 10:07:19 +05:00
thecodrr
11e164f53b chore: bump tinymce-plugins to 1.2.4 2021-10-04 13:58:56 +05:00
thecodrr
299d6ac117 fix: insert newline after image 2021-10-04 13:58:36 +05:00
thecodrr
651d4bf342 chore: bump tinymce-plugins to v1.2.3 2021-10-04 13:51:41 +05:00
thecodrr
7f442bb719 fix: handle multiple duplicate attachment elements 2021-10-04 13:51:11 +05:00
thecodrr
fd79177d4f fix: extend editor interface for progress updates 2021-10-01 12:45:15 +05:00
thecodrr
4b01ea7da7 chore: bump tinymce-plugins to 1.2.2 2021-10-01 11:43:45 +05:00
thecodrr
3fdaab2b0b fix: use editor.dom instead of document for dom access 2021-10-01 11:42:40 +05:00
thecodrr
dbb4ea616a chore: bump tinymce-plugins version to 1.2.1 2021-09-30 10:45:03 +05:00
thecodrr
a1b33a97bd feat: add context toolbar for attachments 2021-09-30 10:44:39 +05:00
thecodrr
29d165ef77 chore: bump tinymce-plugins to v1.2.0 2021-09-30 09:21:04 +05:00
thecodrr
600972cd29 tinymce-plugins: add attachments handler plugin 2021-09-30 09:16:53 +05:00
thecodrr
6a91986669 fix: Cannot read property 'listLanguages' of undefined 2021-09-29 12:36:18 +05:00
thecodrr
3956e21da8 tinymce-plugins: bump version to 1.1.5 2021-09-29 12:33:31 +05:00
thecodrr
c98b0a4818 fix: e.data can sometimes be undefined 2021-09-29 12:33:09 +05:00
thecodrr
544df95078 feat: enable all hljs languages (#28) 2021-09-29 12:27:49 +05:00
thecodrr
3d423e6718 feat: add fix for swiftkey formatting quirk 2021-09-29 12:27:19 +05:00
296 changed files with 274288 additions and 5668 deletions

8
.changeset/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

10
.changeset/config.json Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "https://unpkg.com/@changesets/config@1.6.3/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}

View File

@@ -1,12 +1,14 @@
# This is a basic workflow to help you get started with Actions
name: CI
name: Docs Deploy
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [main]
paths:
- "docs/**"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
@@ -22,7 +24,7 @@ jobs:
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Use Node.js 15.x
uses: actions/setup-node@v2.1.5
with:
@@ -34,7 +36,7 @@ jobs:
- uses: blbecker/rsync-deploy@v1.0
with:
source_dir: ./docs/public_html
destination_path: ${{ secrets.REMOTE_PATH }}
destination_path: ${{ secrets.REMOTE_DOCS_PATH }}
destination_host: ${{ secrets.REMOTE_HOST }}
deployment_user: ${{ secrets.REMOTE_USER }}
deployment_key: ${{ secrets.REMOTE_KEY }}

32
.github/workflows/enex-tests.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
# This is a basic workflow to help you get started with Actions
name: notesnook/enex tests
# Controls when the action will run.
on:
# Triggers the workflow on push events or manually
workflow_dispatch:
push:
branches: [main]
paths:
- "packages/enex/**"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2.1.5
with:
node-version: 16.x
- run: |
cd packages/enex
npm i
npm run test

41
.github/workflows/importer-deploy.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
# This is a basic workflow to help you get started with Actions
name: Importer Deploy
# Controls when the action will run.
on:
# Triggers the workflow on push events or manually
workflow_dispatch:
push:
branches: [main]
paths:
- "apps/importer/**"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2.1.5
with:
node-version: 16.x
- run: |
cd apps/importer
npm i
npm run build
mv ./build/ ./public_html/
- uses: blbecker/rsync-deploy@v1.0
with:
source_dir: ./apps/importer/public_html/
destination_path: ${{ secrets.REMOTE_IMPORTER_PATH }}
destination_host: ${{ secrets.REMOTE_HOST }}
deployment_user: ${{ secrets.REMOTE_USER }}
deployment_key: ${{ secrets.REMOTE_KEY }}

32
.github/workflows/importer-tests.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
# This is a basic workflow to help you get started with Actions
name: notesnook/importer tests
# Controls when the action will run.
on:
# Triggers the workflow on push events or manually
workflow_dispatch:
push:
branches: [main]
paths:
- "packages/importer/**"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2.1.5
with:
node-version: 16.x
- run: |
cd packages/importer
npm i
npm run test

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.turbo
dist
node_modules

View File

@@ -0,0 +1,19 @@
const { version } = require("./package.json");
const fs = require("fs");
const path = require("path");
const APP_VERSION = version;
const CHANGELOG = fs.readFileSync(path.join(__dirname, "changelog.txt"), {
encoding: "utf8",
});
module.exports = {
all: {
REACT_APP_VERSION: APP_VERSION,
REACT_APP_CHANGELOG: CHANGELOG,
},
release: {
GENERATE_SOURCEMAP: false,
INLINE_RUNTIME_CHUNK: false,
DISABLE_ESLINT_PLUGIN: true,
},
};

23
apps/importer/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -0,0 +1,3 @@
1. 🥳 Support for Standard Notes is here! 🥳
2. Fixed issue with Evernote provider where images got cut off.
3. Fixes issue where some attachments were lost during Evernote .enex import.

39146
apps/importer/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
{
"name": "@notesnook/importer-web",
"version": "1.1.2",
"private": true,
"devDependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/file-saver": "^2.0.4",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-dropzone": "^5.1.0",
"@types/react-modal": "^3.13.1",
"@types/theme-ui": "^0.6.0",
"env-cmd": "^10.1.0",
"react-scripts": "4.0.3",
"typescript": "^4.1.2"
},
"dependencies": {
"@notesnook/importer": "^1.1.3",
"colord": "^2.9.2",
"file-saver": "^2.0.5",
"hash-wasm": "^4.9.0",
"interweave": "^12.9.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-dropzone": "^11.4.2",
"react-icons": "^4.3.1",
"react-modal": "^3.14.4",
"react-select": "^5.2.1",
"theme-ui": "^0.12.1"
},
"scripts": {
"start": "env-cmd -e all react-scripts start",
"build": "env-cmd -e all,release react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Import your notes from any notes app into Notesnook."
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Notesnook Importer</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

71
apps/importer/src/App.css Normal file
View File

@@ -0,0 +1,71 @@
/* open-sans-regular - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 400;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-regular.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 400;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-600 - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 600;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-600.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-600.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-600italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 600;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-600italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-600italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-700 - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 700;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-700.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-700italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 700;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-700italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-700italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

54
apps/importer/src/App.tsx Normal file
View File

@@ -0,0 +1,54 @@
import { Flex } from "@theme-ui/components";
import { ThemeProvider } from "@theme-ui/theme-provider";
import "./App.css";
import { ThemeFactory } from "./theme";
import { useState } from "react";
import { Providers } from "@notesnook/importer/dist/src/providers/providerfactory";
import { StepSeperator } from "./components/StepSeperator";
import { ProviderSelector } from "./components/ProviderSelector";
import { FileSelector } from "./components/FileSelector";
import { ImportResult } from "./components/ImportResult";
import { Hero } from "./components/Hero";
import { Footer } from "./components/Footer";
function App() {
const [selectedProvider, setSelectedProvider] = useState<
Providers | undefined
>();
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
return (
<ThemeProvider theme={ThemeFactory.construct()}>
<Flex sx={{ flexDirection: "column" }}>
<Hero />
<Flex
sx={{
flexDirection: "column",
alignItems: "center",
}}
>
<ProviderSelector onProviderChanged={setSelectedProvider} />
{selectedProvider && (
<>
<StepSeperator />
<FileSelector
provider={selectedProvider}
onFilesChanged={setSelectedFiles}
/>
</>
)}
{selectedFiles.length > 0 && selectedProvider && (
<>
<StepSeperator />
<ImportResult files={selectedFiles} provider={selectedProvider} />
</>
)}
</Flex>
<Footer />
</Flex>
</ThemeProvider>
);
}
export default App;

View File

@@ -0,0 +1,42 @@
import { Flex, FlexProps, Text } from "@theme-ui/components";
import { PropsWithChildren, useState } from "react";
import { IoChevronDown, IoChevronUp } from "react-icons/io5";
type AccordionProps = FlexProps & {
title: string;
color?: string;
};
export function Accordion({
title,
children,
sx,
color,
...restProps
}: PropsWithChildren<AccordionProps>) {
const [isContentHidden, setIsContentHidden] = useState<boolean>(true);
return (
<Flex sx={{ flexDirection: "column", ...sx }} {...restProps}>
<Flex
sx={{
justifyContent: "space-between",
alignItems: "center",
p: 2,
cursor: "pointer",
}}
onClick={() => {
setIsContentHidden((state) => !state);
}}
>
<Text variant="subtitle" sx={{ color }}>
{title}
</Text>
{isContentHidden ? (
<IoChevronDown size={16} color={color} />
) : (
<IoChevronUp size={16} color={color} />
)}
</Flex>
{!isContentHidden && children}
</Flex>
);
}

View File

@@ -0,0 +1,113 @@
import { Flex, Input, Text } from "@theme-ui/components";
import { ProviderFactory } from "@notesnook/importer";
import { useCallback, useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import { IProvider } from "@notesnook/importer/dist/src/providers/provider";
import { Providers } from "@notesnook/importer/dist/src/providers/providerfactory";
import { StepContainer } from "./StepContainer";
import { Accordion } from "./Accordion";
type FileSelectorProps = {
provider?: Providers;
onFilesChanged: (files: File[]) => void;
};
export function FileSelector(props: FileSelectorProps) {
const { provider: providerName, onFilesChanged } = props;
const [files, setFiles] = useState<File[]>([]);
const [provider, setProvider] = useState<IProvider | undefined>();
const onDrop = useCallback((acceptedFiles: File[]) => {
setFiles((files) => {
const newFiles = [...acceptedFiles, ...files];
return newFiles;
});
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: provider?.supportedExtensions?.concat(".zip"),
});
useEffect(() => {
onFilesChanged(files);
}, [files, onFilesChanged]);
useEffect(() => {
setFiles([]);
setProvider(undefined);
if (!providerName) return;
setProvider(ProviderFactory.getProvider(providerName));
}, [providerName]);
return (
<StepContainer sx={{ flexDirection: "column", alignItems: "stretch" }}>
<Text variant="title">Select {provider?.name} files</Text>
<Flex
{...getRootProps()}
sx={{
justifyContent: "center",
alignItems: "center",
height: 200,
border: "2px dashed var(--theme-ui-colors-border)",
borderRadius: "default",
mt: 2,
}}
>
<Input {...getInputProps()} />
<Text variant="body" sx={{ textAlign: "center" }}>
{isDragActive
? "Drop the files here"
: "Drag & drop files here, or click to select files"}
<br />
<Text variant="subBody">
Only {provider?.supportedExtensions.join(", ")} files are supported.
You can also select .zip files containing{" "}
{provider?.supportedExtensions.join(", ")} files.
</Text>
</Text>
</Flex>
{files.length > 0 ? (
<Accordion
title={`${files.length} ${
files.length > 1 ? "files" : "file"
} selected`}
sx={{
border: "1px solid var(--theme-ui-colors-border)",
mt: 2,
borderRadius: "default",
}}
>
<Flex
sx={{ flexDirection: "column", overflowY: "auto", maxHeight: 400 }}
>
{files.map((file, index) => (
<Flex
sx={{
flexDirection: "column",
p: 2,
bg: index % 2 ? "transparent" : "bgSecondary",
cursor: "pointer",
":hover": {
bg: "hover",
},
}}
onClick={() => {
setFiles((files) => {
const _files = files.slice();
_files.splice(index, 1);
return _files;
});
}}
title="Click to remove"
>
<Text variant="body">{file.name}</Text>
</Flex>
))}
</Flex>
</Accordion>
) : null}
</StepContainer>
);
}

View File

@@ -0,0 +1,21 @@
import { Flex, Text } from "@theme-ui/components";
import { appVersion } from "../utils/version";
export function Footer() {
return (
<Flex
sx={{
flexDirection: "column",
mt: 100,
pt: 50,
pb: 50,
borderTop: "1px solid var(--theme-ui-colors-border)",
alignItems: "center",
justifyContent: "center",
}}
>
<Text variant="body">Notesnook Importer (v{appVersion})</Text>
<Text variant="subBody">© 2021 Streetwriters LLC</Text>
</Flex>
);
}

View File

@@ -0,0 +1,63 @@
import { Flex, Link, Text } from "@theme-ui/components";
import { appVersion } from "../utils/version";
export function Hero() {
return (
<Flex
sx={{
flexDirection: "column",
mt: 150,
mb: 100,
justifyContent: "center",
alignItems: "center",
}}
>
<Text variant="heading" sx={{ textAlign: "center" }}>
Notesnook Importer
</Text>
<Text
sx={{
fontSize: "title",
textAlign: "center",
color: "fontTertiary",
}}
>
Import your notes from any notes app into Notesnook.
</Text>
<Flex sx={{ mt: 2 }}>
<Text variant="body" sx={{ px: 1 }}>
v{appVersion}
</Text>
<Link
href="https://github.com/streetwriters/notesnook"
variant="text.body"
sx={{ px: 1, borderLeft: "1px solid var(--theme-ui-colors-border)" }}
>
Github
</Link>
<Link
href="https://app.notesnook.com/"
variant="text.body"
sx={{ px: 1, borderLeft: "1px solid var(--theme-ui-colors-border)" }}
>
Notesnook Web
</Link>
</Flex>
<Flex
sx={{
bg: "bgSecondary",
flexDirection: "column",
width: 400,
mt: 4,
p: 2,
borderRadius: "default",
}}
>
<Text variant="subtitle">What's new in v{appVersion}</Text>
<Text variant="body" sx={{ whiteSpace: "pre-wrap" }}>
{process.env.REACT_APP_CHANGELOG}
</Text>
</Flex>
</Flex>
);
}

View File

@@ -0,0 +1,39 @@
import { Button, Flex, Text } from "@theme-ui/components";
import { Accordion } from "./Accordion";
import { TransformError } from "@notesnook/importer/dist/src/utils/transformerror";
type ImportErrorsProps = {
errors: TransformError[];
};
export function ImportErrors(props: ImportErrorsProps) {
return (
<Accordion
title={`${props.errors.length} errors occured`}
sx={{ bg: "errorBg", borderRadius: "default", mt: 2 }}
color="#E53935"
>
<Flex sx={{ flexDirection: "column", px: 2, pb: 2 }}>
<Text variant="body" sx={{ color: "error" }}>
{props.errors.map((error, index) => (
<>
{index + 1}. {error.message} ({error.file.name})
<br />
</>
))}
</Text>
<Button
sx={{ bg: "error", color: "static", alignSelf: "start", mt: 2 }}
onClick={() =>
window.open(
"https://github.com/streetwriters/notesnook/issues/new",
"_blank"
)
}
>
Send us a bug report
</Button>
</Flex>
</Accordion>
);
}

View File

@@ -0,0 +1,47 @@
import { Button, Text } from "@theme-ui/components";
import { Accordion } from "./Accordion";
type ImportHelpProps = {
onDownload: () => void;
};
export function ImportHelp(props: ImportHelpProps) {
return (
<Accordion
title="How to import your notes into Notesnook?"
sx={{ bg: "bgSecondary", mt: 2, borderRadius: "default" }}
>
<Text
as="ol"
variant="body"
sx={{
lineHeight: "24px",
paddingInlineStart: 30,
pb: 2,
}}
>
<Text as="li">
<Button variant="primary" sx={{ py: 0 }} onClick={props.onDownload}>
Download the ZIP file
</Button>{" "}
containing your notes
</Text>
<Text as="li">
<a href="https://app.notesnook.com/">Open Notesnook</a> and make sure
you are logged in.
</Text>
<Text as="li">
Go to <b>Settings</b>
</Text>
<Text as="li">
Expand the section titled <b>Notesnook Importer</b>
</Text>
<Text as="li">
Click on <b>Import from ZIP file</b>
</Text>
<Text as="li">Select the downloaded ZIP file</Text>
<Text as="li">Your notes should appear in the app.</Text>
</Text>
</Accordion>
);
}

View File

@@ -0,0 +1,113 @@
import { Button, Text } from "@theme-ui/components";
import { pack, transform } from "@notesnook/importer";
import { useCallback, useEffect, useState } from "react";
import {
ProviderResult,
ProviderSettings,
} from "@notesnook/importer/dist/src/providers/provider";
import { Providers } from "@notesnook/importer/dist/src/providers/providerfactory";
import { IFile } from "@notesnook/importer/dist/src/utils/file";
import { xxhash64 } from "hash-wasm";
import { Note } from "@notesnook/importer/dist/src/models/note";
import { StepContainer } from "./StepContainer";
import { NotePreview } from "./NotePreview";
import { ImportErrors } from "./ImportErrors";
import { ImportHelp } from "./ImportHelp";
import { saveAs } from "file-saver";
import { NotesList } from "./NotesList";
type ResultProps = {
files: File[];
provider: Providers | undefined;
};
type Progress = {
total: number;
done: number;
};
const settings: ProviderSettings = {
hasher: { type: "xxh64", hash: (data) => xxhash64(data) },
};
export function ImportResult(props: ResultProps) {
const { provider, files } = props;
const [progress, setProgress] = useState<Progress>({ total: 0, done: 0 });
const [result, setResult] = useState<ProviderResult | undefined>();
const [selectedNote, setSelectedNote] = useState<Note | undefined>();
useEffect(() => {
(async () => {
if (!provider) return;
setProgress({ total: 0, done: 0 });
let result: ProviderResult = { notes: [], errors: [] };
for (let file of files) {
const providerFile: IFile = {
name: file.name,
data: await file.arrayBuffer(),
modifiedAt: file.lastModified,
};
const transformResult = await transform(
[providerFile],
provider,
settings
);
result.notes.push(...transformResult.notes);
result.errors.push(...transformResult.errors);
setProgress((p) => ({ total: files.length, done: p.done + 1 }));
}
setProgress({ total: 0, done: 0 });
setResult(result);
})();
}, [provider, files]);
const downloadAsZip = useCallback(() => {
if (!result) return;
const packed = pack(result.notes);
saveAs(
new Blob([packed], { type: "application/zip" }),
`notesnook-importer.zip`
);
}, [result]);
return (
<StepContainer
sx={{
flexDirection: "column",
alignItems: "stretch",
}}
>
<Text variant="title">Your notes are ready for download</Text>
{progress.total > 0 ? (
<Text variant="body">
Processing files ({progress.done}/{progress.total})
</Text>
) : result ? (
<>
<Text variant="body" sx={{ color: "fontTertiary" }}></Text>
<NotesList
notes={result?.notes}
filesLength={files.length}
onNoteSelected={(note) => setSelectedNote(note)}
/>
{result.errors.length > 0 && <ImportErrors errors={result.errors} />}
<ImportHelp onDownload={downloadAsZip} />
<Button
variant="primary"
sx={{ alignSelf: "center", mt: 2 }}
onClick={downloadAsZip}
>
Download ZIP file
</Button>
</>
) : null}
{selectedNote && (
<NotePreview
note={selectedNote}
onClose={() => setSelectedNote(undefined)}
/>
)}
</StepContainer>
);
}

View File

@@ -0,0 +1,150 @@
import { Button, Flex, Text } from "@theme-ui/components";
import { IoStarOutline } from "react-icons/io5";
import { GrPin } from "react-icons/gr";
import { MdCircle, MdClose, MdOutlineBook } from "react-icons/md";
import { Markup } from "interweave";
import Modal from "react-modal";
import { Note } from "@notesnook/importer/dist/src/models/note";
Modal.setAppElement("#root");
type NotePreviewProps = {
note: Note;
onClose: () => void;
};
export function NotePreview(props: NotePreviewProps) {
const {
title,
content,
dateEdited,
dateCreated,
favorite,
color,
pinned,
notebooks,
tags,
attachments,
} = props.note;
return (
<Modal
isOpen={true}
contentLabel={title}
style={{
content: {
borderRadius: 10,
border: "1px solid var(--theme-ui-colors-border)",
boxShadow: "0px 0px 20px 0px #00000011",
},
}}
>
<Flex sx={{ flexDirection: "column" }}>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="subBody">
This preview is not an exact representation of how the note will
appear in Notesnook.
</Text>
<Button
variant="secondary"
sx={{
bg: "transparent",
display: "flex",
alignSelf: "end",
p: 0,
m: 0,
alignItems: "center",
}}
onClick={props.onClose}
>
<MdClose size={24} />
</Button>
</Flex>
<Text as="h1" variant="subheading">
{title}
</Text>
<Flex sx={{ alignItems: "center" }}>
{color && (
<MdCircle color={color} size={14} style={{ marginRight: 5 }} />
)}
{favorite && <IoStarOutline style={{ marginRight: 5 }} />}
{pinned && <GrPin size={12} style={{ marginRight: 5 }} />}
{dateCreated && (
<>
<Text variant="subBody">
Created on: {formatDate(dateCreated)}
</Text>
</>
)}
{dateEdited && (
<>
<MdCircle
color="#5b5b5b"
size={7}
style={{ marginLeft: 3, marginRight: 3 }}
/>
<Text variant="subBody">
Last modified: {formatDate(dateEdited)}
</Text>
</>
)}
{attachments && (
<>
<MdCircle
color="#5b5b5b"
size={7}
style={{ marginLeft: 3, marginRight: 3 }}
/>
<Text variant="subBody">{attachments.length} attachments</Text>
</>
)}
</Flex>
<Flex my={1}>
{notebooks?.map((notebook) => (
<Flex
sx={{
alignItems: "center",
bg: "bgSecondary",
mr: 1,
p: 1,
py: "2px",
border: "1px solid var(--theme-ui-colors-border)",
borderRadius: "default",
color: "fontTertiary",
}}
>
<MdOutlineBook size={11} />
<Text variant="subBody" sx={{ ml: "2px" }}>
{notebook.notebook} &gt; {notebook.topic}
</Text>
</Flex>
))}
{tags?.map((tag) => (
<Text
variant="subBody"
sx={{
bg: "bgSecondary",
mr: 1,
p: 1,
py: "2px",
border: "1px solid var(--theme-ui-colors-border)",
borderRadius: "default",
color: "fontTertiary",
}}
>
#{tag}
</Text>
))}
</Flex>
<Text variant="body">
<Markup content={content?.data} />
</Text>
</Flex>
</Modal>
);
}
function formatDate(date: number) {
return new Date(date).toLocaleString(undefined, {
dateStyle: "short",
timeStyle: "short",
});
}

View File

@@ -0,0 +1,62 @@
import { Flex, Text } from "@theme-ui/components";
import { Note } from "@notesnook/importer/dist/src/models/note";
import { Accordion } from "./Accordion";
type NotesListProps = {
notes: Note[];
filesLength: number;
onNoteSelected: (note: Note) => void;
};
export function NotesList(props: NotesListProps) {
const { notes, filesLength, onNoteSelected } = props;
return (
<Accordion
title={`${notes.length} notes found in ${filesLength} ${
filesLength > 1 ? "files" : "file"
}`}
sx={{
border: "1px solid var(--theme-ui-colors-border)",
mt: 2,
borderRadius: "default",
}}
>
<Flex
sx={{
flexDirection: "column",
overflowY: "auto",
maxHeight: 300,
}}
>
{notes.map((note, index) => (
<Flex
sx={{
flexDirection: "column",
p: 2,
bg: index % 2 ? "transparent" : "bgSecondary",
cursor: "pointer",
":hover": {
bg: "hover",
},
}}
onClick={() => {
onNoteSelected(note);
}}
title="Click to preview"
>
<Text variant="body">{note.title}</Text>
{note.dateEdited && (
<Text variant="subBody">
Last modified on:{" "}
{new Date(note.dateEdited).toLocaleString(undefined, {
dateStyle: "short",
timeStyle: "short",
})}
</Text>
)}
</Flex>
))}
</Flex>
</Accordion>
);
}

View File

@@ -0,0 +1,53 @@
import { Flex, Select, Text } from "@theme-ui/components";
import { ProviderFactory } from "@notesnook/importer";
import { Providers } from "@notesnook/importer/dist/src/providers/providerfactory";
import { StepContainer } from "./StepContainer";
type ProviderSelectorProps = {
onProviderChanged: (provider: Providers) => void;
};
export function ProviderSelector(props: ProviderSelectorProps) {
return (
<StepContainer sx={{ flexDirection: "column" }}>
<Flex sx={{ justifyContent: "space-between" }}>
<Text variant="title">Choose a provider to import from</Text>
<Select
sx={{
p: 0,
m: 0,
px: 2,
border: "1px solid var(--theme-ui-colors-border)",
outline: "none",
":hover": {
borderColor: "hover",
},
":active": {
borderColor: "active",
},
fontFamily: "body",
fontSize: "body",
width: 150,
}}
onChange={(e) => {
const providerName: Providers = e.target.value as Providers;
props.onProviderChanged(providerName);
}}
>
<option value=""></option>
{ProviderFactory.getAvailableProviders().map((provider) => (
<option value={provider}>
{ProviderFactory.getProvider(provider as Providers).name}
</option>
))}
</Select>
</Flex>
<Text variant="body" sx={{ color: "fontTertiary" }}>
Can't find your notes app in the list?{" "}
<a href="https://github.com/streetwriters/notesnook/issues/new">
Send us a request.
</a>
</Text>
</StepContainer>
);
}

View File

@@ -0,0 +1,22 @@
import { Flex, FlexProps } from "@theme-ui/components";
export function StepContainer({
children,
sx,
...restProps
}: React.PropsWithChildren<FlexProps>) {
return (
<Flex
sx={{
width: "40%",
boxShadow: "0px 0px 20px 0px #00000011",
p: 4,
borderRadius: "default",
...sx,
}}
{...restProps}
>
{children}
</Flex>
);
}

View File

@@ -0,0 +1,5 @@
import { Box } from "@theme-ui/components";
export function StepSeperator() {
return <Box sx={{ height: 150, width: 2, bg: "bgSecondary" }} />;
}

View File

View File

@@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

1
apps/importer/src/react-app-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="react-scripts" />

View File

@@ -0,0 +1,28 @@
import { colord } from "colord";
import { StaticColors } from "./static";
export class DarkColorScheme {
static construct(accent: string) {
return {
primary: colord(accent).toHex(),
placeholder: colord("#ffffff")
.alpha(0.6)
.toHex(),
background: "#1f1f1f",
bgTransparent: "#1f1f1f99",
accent: "#000",
bgSecondary: "#2b2b2b",
bgSecondaryText: "#A1A1A1",
border: "#2b2b2b",
hover: "#3b3b3b",
fontSecondary: "#000",
fontTertiary: "#A1A1A1",
text: "#d3d3d3",
overlay: "rgba(53, 53, 53, 0.5)",
secondary: "black",
icon: "#dbdbdb",
disabled: "#5b5b5b",
...StaticColors.construct(accent),
};
}
}

View File

@@ -0,0 +1,14 @@
import { DarkColorScheme } from "./dark";
import { LightColorScheme } from "./light";
const colorSchemes = {
dark: DarkColorScheme,
light: LightColorScheme,
};
class ColorSchemeFactory {
static construct<TTheme extends keyof typeof colorSchemes>(theme: TTheme) {
return colorSchemes[theme].construct("#008837");
}
}
export default ColorSchemeFactory;

View File

@@ -0,0 +1,29 @@
import { colord } from "colord";
import { StaticColors } from "./static";
export class LightColorScheme {
static construct(accent: string) {
return {
primary: colord(accent).toHex(),
background: "white",
bgTransparent: "#ffffff99",
accent: "white",
bgSecondary: "#f7f7f7",
bgSecondaryText: "#5E5E5E",
border: "#e7e7e7",
hover: "#f0f0f0",
active: "#ababab",
fontSecondary: "white",
fontTertiary: "#656565",
text: "#202124",
overlay: "rgba(0, 0, 0, 0.1)",
secondary: "white",
icon: "#3b3b3b",
disabled: "#9b9b9b",
placeholder: colord("#000000")
.alpha(0.6)
.toHex(),
...StaticColors.construct(accent),
};
}
}

View File

@@ -0,0 +1,31 @@
import { colord } from "colord";
export class StaticColors {
static construct(accent: string) {
return {
shade: colord(accent)
.alpha(0.1)
.toRgbString(),
textSelection: colord(accent)
.alpha(0.2)
.toRgbString(),
dimPrimary: colord(accent)
.alpha(0.7)
.toRgbString(),
transparent: "transparent",
static: "white",
error: "#E53935",
errorBg: "#E5393520",
success: "#4F8A10",
warn: "#FF5722",
favorite: "#ffd700",
red: "#f44336",
orange: "#FF9800",
yellow: "#f0c800",
green: "#4CAF50",
blue: "#2196F3",
purple: "#9568ED",
gray: "#9E9E9E",
};
}
}

View File

@@ -0,0 +1,13 @@
export class FontSizeFactory {
static construct() {
return {
heading: "48px",
subheading: "24px",
title: "16px",
subtitle: "14px",
body: "14px",
input: "12px",
subBody: "12px",
};
}
}

View File

@@ -0,0 +1,19 @@
import { FontSizeFactory } from "./fontsize";
export class FontFactory {
static construct() {
return {
fontSizes: FontSizeFactory.construct(),
fontWeights: {
normal: 400,
body: 400,
heading: 600,
bold: 600,
},
fonts: {
body: `Open Sans,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Oxygen-Sans,Ubuntu,Cantarell,sans-serif;`,
heading: `Open Sans,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Oxygen-Sans,Ubuntu,Cantarell,sans-serif;`,
},
};
}
}

View File

@@ -0,0 +1,24 @@
import ColorSchemeFactory from "./colorscheme";
import VariantsFactory from "./variants";
import { FontFactory } from "./font";
import { Theme } from "theme-ui";
export class ThemeFactory {
static construct(): Theme {
return {
breakpoints: ["480px", "1000px", "1000px"],
space: [0, 5, 10, 15, 20, 25, 30, 35],
sizes: { full: "100%", half: "50%" },
radii: { none: 0, default: 10 },
colors: {
modes: {
dark: ColorSchemeFactory.construct("dark"),
light: ColorSchemeFactory.construct("light"),
},
},
rawColors: ColorSchemeFactory.construct("light"),
...FontFactory.construct(),
...new VariantsFactory(),
};
}
}

View File

@@ -0,0 +1,76 @@
class ButtonFactory {
constructor() {
return {
default: new Default(),
primary: new Primary(),
secondary: new Secondary(),
tertiary: new Tertiary(),
};
}
}
export default ButtonFactory;
class Default {
constructor() {
return {
bg: "transparent",
fontFamily: "body",
fontWeight: "body",
fontSize: "body",
borderRadius: "5px",
cursor: "pointer",
p: 1,
px: 2,
transition: "filter 200ms ease-in, box-shadow 200ms ease-out",
":hover:not(:disabled)": {
filter: "brightness(90%)",
},
":active": {
filter: "brightness(98%)",
},
outline: "none",
":focus-visible:not(:active)": {
boxShadow: "0px 0px 0px 2px var(--text)",
},
":disabled": {
opacity: 0.5,
cursor: "not-allowed",
},
};
}
}
class Primary {
constructor() {
return {
variant: "buttons.default",
color: "static",
bg: "primary",
};
}
}
class Secondary {
constructor() {
return {
variant: "buttons.default",
color: "text",
bg: "border",
};
}
}
class Tertiary {
constructor() {
return {
variant: "buttons.default",
color: "text",
bg: "transparent",
border: "2px solid",
borderColor: "border",
":hover": {
borderColor: "primary",
},
};
}
}

View File

@@ -0,0 +1,14 @@
import ButtonFactory from "./button";
import InputFactory from "./input";
import TextFactory from "./text";
class VariantFactory {
constructor() {
return {
buttons: new ButtonFactory(),
forms: new InputFactory(),
text: new TextFactory(),
};
}
}
export default VariantFactory;

View File

@@ -0,0 +1,64 @@
class InputFactory {
constructor() {
return {
input: new Default(),
error: new Error(),
clean: new Clean(),
};
}
}
export default InputFactory;
class Default {
constructor() {
return {
borderRadius: "default",
border: "none",
// borderColor: "border",
boxShadow: "0px 0px 0px 1px var(--border) inset",
fontFamily: "body",
fontWeight: "body",
fontSize: "input",
color: "text",
outline: "none",
":focus": {
boxShadow: "0px 0px 0px 1.5px var(--primary) inset",
},
":hover:not(:focus)": {
boxShadow: "0px 0px 0px 1px var(--dimPrimary) inset",
},
};
}
}
class Clean {
constructor() {
return {
variant: "forms.input",
outline: "none",
boxShadow: "none",
":focus": {
boxShadow: "none",
},
":hover:not(:focus)": {
boxShadow: "none",
},
};
}
}
class Error {
constructor() {
return {
variant: "forms.input",
boxShadow: "0px 0px 0px 1px var(--error) inset",
outline: "none",
":focus": {
boxShadow: "0px 0px 0px 1.5px var(--error) inset",
},
":hover:not(:focus)": {
boxShadow: "0px 0px 0px 1px var(--error) inset",
},
};
}
}

View File

@@ -0,0 +1,85 @@
class TextFactory {
constructor() {
return {
default: new Default(),
heading: new Heading(),
subheading: new Subheading(),
title: new Title(),
subtitle: new Subtitle(),
body: new Body(),
subBody: new SubBody(),
error: new Error(),
};
}
}
export default TextFactory;
class Default {
constructor() {
return {
color: "text",
fontFamily: "body",
};
}
}
class Heading {
constructor() {
return {
variant: "text.default",
fontFamily: "heading",
fontWeight: "bold",
fontSize: "heading",
};
}
}
class Subheading {
constructor() {
return {
variant: "text.heading",
fontSize: "subheading",
};
}
}
class Title {
constructor() {
return {
variant: "text.heading",
fontSize: "title",
fontWeight: "bold",
};
}
}
class Subtitle {
constructor() {
return {
variant: "text.heading",
fontSize: "subtitle",
fontWeight: "bold",
};
}
}
class Body {
constructor() {
return { variant: "text.default", fontSize: "body" };
}
}
class SubBody {
constructor() {
return {
variant: "text.default",
fontSize: "subBody",
color: "fontTertiary",
};
}
}
class Error {
constructor() {
return { variant: "text.default", fontSize: "subBody", color: "error" };
}
}

View File

@@ -0,0 +1 @@
export const appVersion = process.env.REACT_APP_VERSION;

View File

@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"exclude": ["node_modules"],
"include": ["src"]
}

View File

@@ -1,5 +1,6 @@
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const { JSDOM } = require("jsdom");
const generateRobot = require("./generateRobot");
const generateSitemap = require("./generateSitemap");
@@ -43,15 +44,16 @@ function createTrackerScript(document) {
return script;
}
(function () {
(function() {
const output = buildDocs();
console.log(output)
if (!output.includes("0 errors")) {
console.error(output);
return;
}
console.log("Docs generated!");
const outputPath = output.split("\n")[2].trim().substring(8).trim();
const outputPath = /OUTPUT: (.*$)/gm.exec(output)[1];
console.log(`Documentation output path:`, outputPath);

View File

@@ -11,9 +11,10 @@ If you face any problem while importing your data from other note apps, please r
Notesnook importer is your one stop location to import all your notes from any notes app. We have added support for most of the popular note apps and common export formats such as markdown, html and text files.
<img src="../static/notesnook_importer.png" alt="Notesnook importer"/>
<img src="/static/notesnook_importer.png" alt="Notesnook importer"/>
## Try it out
You can try out the importer by going to [https://importer.notesnook.com](https://importer.notesnook.com) to import your notes from any notes app.
## Supported note apps and formats
@@ -32,5 +33,5 @@ You can try out the importer by going to [https://importer.notesnook.com](https:
**Don't see your notes app?** No worries, create an issue on [github](https://github.com/streetwriters/notesnook/issues)
## Is it safe to import?
Not a single byte of your data from other apps is sent to our servers. Everything is processed 100% on the client side inside this browser.
Not a single byte of your data from other apps is sent to our servers. Everything is processed 100% on the client side inside this browser.

View File

@@ -10,24 +10,20 @@ The following steps will help you import your notes from Bear notes easily.
1. Open Bear Notes app on Desktop.
2. Click on `File` and select `Backup Notes`
<img style="margin-bottom:15px;" src="../static/bear_import_step_1.png" alt="Click on `File` and select `Backup Notes`"/>
<img style="margin-bottom:15px;" src="/static/bear_import_step_1.png" alt="Click on `File` and select `Backup Notes`"/>
2. Select the location where you want to store the backup file. It will be a `.bearbk` file.
<img style="margin-bottom:15px;" src="../static/bear_import_step_2.png" alt="Select the location where you want to store the backup file. It will be a `.bearbk` file."/>
3. Select the location where you want to store the backup file. It will be a `.bearbk` file.
<img style="margin-bottom:15px;" src="/static/bear_import_step_2.png" alt="Select the location where you want to store the backup file. It will be a `.bearbk` file."/>
4. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Bear Notes` from list of apps.
<img style="margin-bottom:15px;" src="../static/bearnotes_import_step_3.png" alt="Go to https://importer.notesnook.com and select `Bear Notes` from list of apps."/>
<img style="margin-bottom:15px;" src="/static/bearnotes_import_step_3.png" alt="Go to https://importer.notesnook.com and select `Bear Notes` from list of apps."/>
5. Drop the `.bearbk` backup file you exported earlier from Bear Notes in the box or click anywhere to open system file picker to select the file
<img style="margin-bottom:15px;" src="../static/bear_import_step_4.png" alt="Drop the `.bearbk` backup file you exported earlier from Bear Notes in the box or click anywhere to open system file picker to select the file."/>
<img style="margin-bottom:15px;" src="/static/bear_import_step_4.png" alt="Drop the `.bearbk` backup file you exported earlier from Bear Notes in the box or click anywhere to open system file picker to select the file."/>
6. Click on `Import 1 file` button to start importing.
7. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -10,26 +10,22 @@ The following steps will help you import your notes from EverNote easily.
1. Open EverNote app on Desktop.
2. Go to `Notebooks` from the side menu
<img style="margin-bottom:15px;" src="../static/evernote_import_step_1.png" alt="Go to `Notebooks` from the side menu"/>
<img style="margin-bottom:15px;" src="/static/evernote_import_step_1.png" alt="Go to `Notebooks` from the side menu"/>
2. Click on the `three-dot` button on each notebook and click on `Export Notebook`
<img style="margin-bottom:15px;" src="../static/evernote_import_step_2.png" alt="Click on the `three-dot` button on each notebook and click on `Export Notebook`"/>
3. Click on the `three-dot` button on each notebook and click on `Export Notebook`
<img style="margin-bottom:15px;" src="/static/evernote_import_step_2.png" alt="Click on the `three-dot` button on each notebook and click on `Export Notebook`"/>
4. Choose `.enex` format and click on `Export` and save it to desired location.
<img style="margin-bottom:15px;" src="../static/evernote_import_step_3.png" alt="Choose `.enex` format and click on `Export`"/>
<img style="margin-bottom:15px;" src="/static/evernote_import_step_3.png" alt="Choose `.enex` format and click on `Export`"/>
5. Repeat this for all your Notebooks.
6. Drop the `.enex` backup files you exported earlier from EverNote in the box or click anywhere to open system file picker to select the file
<img style="margin-bottom:15px;" src="../static/evernote_import_step_4.png" alt="Drop the `.enex` backup files you exported earlier from EverNote in the box or click anywhere to open system file picker to select the file"/>
<img style="margin-bottom:15px;" src="/static/evernote_import_step_4.png" alt="Drop the `.enex` backup files you exported earlier from EverNote in the box or click anywhere to open system file picker to select the file"/>
6. Click on `Import N files` button to start importing.
7. Click on `Import N files` button to start importing.
7. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="From the list of formats to import, select Plain Text."/>
8. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="From the list of formats to import, select Plain Text."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -10,24 +10,23 @@ The following steps will help you import your notes from Google Keep easily.
1. Go to [Google Takeout](https://takeout.google.com/settings/takeout) and Login to your account.
2. On Google Takeout Page, first click on `Deselect all` then scroll down and select `Keep` and click `Next Step`.
<img style="margin-bottom:15px;" src="../static/googlekeep_import_step_1.png" alt="On Google Takeout Page, first click on `Deselect all` then scroll down and select `Keep` and click `Next Step`."/>
<img style="margin-bottom:15px;" src="/static/googlekeep_import_step_1.png" alt="On Google Takeout Page, first click on `Deselect all` then scroll down and select `Keep` and click `Next Step`."/>
3. Click on create export
<img style="margin-bottom:15px;" src="../static/googlekeep_import_step_2.png" alt="Click on create export"/>
<img style="margin-bottom:15px;" src="/static/googlekeep_import_step_2.png" alt="Click on create export"/>
4. Download your exported file.
<img style="margin-bottom:15px;" src="../static/googlekeep_import_step_3.png" alt="Download your exported file."/>
<img style="margin-bottom:15px;" src="/static/googlekeep_import_step_3.png" alt="Download your exported file."/>
5. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Google Keep` from list of apps.
<img style="margin-bottom:15px;" src="../static/googlekeep_import_step_4.png" alt="Go to [Notesnook Importer](https://importer.notesnook.com) and select `Google Keep` from list of apps."/>
<img style="margin-bottom:15px;" src="/static/googlekeep_import_step_4.png" alt="Go to [Notesnook Importer](https://importer.notesnook.com) and select `Google Keep` from list of apps."/>
6. Drop the .zip backup file(s) you exported earlier from Google Takeout in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="../static/googlekeep_import_step_5.png" alt="Drop the .zip backup file(s) you exported earlier from Google Takeout in the box or click anywhere to open system file picker to select the backup."/>
<img style="margin-bottom:15px;" src="/static/googlekeep_import_step_5.png" alt="Drop the .zip backup file(s) you exported earlier from Google Takeout in the box or click anywhere to open system file picker to select the backup."/>
7. Click on `Import N files` button to start importing.
8. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,18 +2,19 @@
label: Html files
order: 800
---
# How do I import notes from html files?
To import html files to notesnook go to Notesnook Importer on your PC/Laptop.
1. From the list of formats to import, select "Html file".
<img style="margin-bottom:15px;" src="../static/html_import_step_1.png" alt="From the list of formats to import, select Html file."/>
<img style="margin-bottom:15px;" src="/static/html_import_step_1.png" alt="From the list of formats to import, select Html file."/>
2. Drop your text files or click anywhere inside the box to browse and select your html files.
<img style="margin-bottom:15px;" src="../static/html_import_step_2.png" alt="Drop your text files or click anywhere inside the box to browse and select your html files."/>
<img style="margin-bottom:15px;" src="/static/html_import_step_2.png" alt="Drop your text files or click anywhere inside the box to browse and select your html files."/>
3. Click on import files button on bottom right corner to start importing files
4. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,27 +2,24 @@
label: Joplin
order: -100
---
# How do I import notes from Joplin notes app?
The following steps will help you import your notes from Joplin easily.
1. Open Joplin app on Desktop.
2. Click on `File` and select `Export All -> JEX - Joplin Export File` and save it in desired location.
<img style="margin-bottom:15px;" src="../static/joplin_import_step_1.png" alt="Click on `File` and select `Export All -> JEX - Joplin Export File`"/>
<img style="margin-bottom:15px;" src="/static/joplin_import_step_1.png" alt="Click on `File` and select `Export All -> JEX - Joplin Export File`"/>
4) Go to [Notesnook Importer](https://importer.notesnook.com) and select `Joplin` from list of apps.
<img style="margin-bottom:15px;" src="/static/joplin_import_step_2.png" alt=" Go to Notesnook Importer https://importer.notesnook.com and select `Joplin` from list of apps."/>
4. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Joplin` from list of apps.
<img style="margin-bottom:15px;" src="../static/joplin_import_step_2.png" alt=" Go to Notesnook Importer https://importer.notesnook.com and select `Joplin` from list of apps."/>
5) Drop the .jex backup file you exported earlier from Joplin in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="/static/joplin_import_step_3.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
5. Drop the .jex backup file you exported earlier from Joplin in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="../static/joplin_import_step_3.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
6) Click on `Import 1 file` button to start importing.
6. Click on `Import 1 file` button to start importing.
7. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
7) Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,18 +2,19 @@
label: Markdown files
order: 700
---
# How do I import notes from markdown files?
To import markdown files to notesnook go to Notesnook Importer on your PC/Laptop.
1. From the list of formats to import, select "Markdown file".
<img style="margin-bottom:15px;" src="../static/markdown_import_step_1.png" alt="From the list of formats to import, select Markdown file."/>
<img style="margin-bottom:15px;" src="/static/markdown_import_step_1.png" alt="From the list of formats to import, select Markdown file."/>
2. Drop your markdown files or click anywhere inside the box to browse and select your markdown files.
<img style="margin-bottom:15px;" src="../static/markdown_import_step_2.png" alt="Drop your markdown files or click anywhere inside the box to browse and select your markdown files."/>
<img style="margin-bottom:15px;" src="/static/markdown_import_step_2.png" alt="Drop your markdown files or click anywhere inside the box to browse and select your markdown files."/>
3. Click on import files button on bottom right corner to start importing files
4. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -8,22 +8,18 @@ order: 600
The following steps will help you import your notes from OneNote easily.
1. Go to [Notesnook Importer](https://importer.notesnook.com) and select `OneNote` from list of apps.
<img style="margin-bottom:15px;" src="../static/onenote_import_step_1.png" alt="Go to Notesnook Importer]https://importer.notesnook.com and select `OneNote` from list of apps."/>
<img style="margin-bottom:15px;" src="/static/onenote_import_step_1.png" alt="Go to Notesnook Importer]https://importer.notesnook.com and select `OneNote` from list of apps."/>
2. Click on `Sign in with Microsoft`
<img style="margin-bottom:15px;" src="../static/onenote_import_step_2.png" alt="Click on `Sign in with Microsoft`"/>
<img style="margin-bottom:15px;" src="/static/onenote_import_step_2.png" alt="Click on `Sign in with Microsoft`"/>
3. Login to your account
<img style="margin-bottom:15px;" src="../static/onenote_import_step_3.png" alt="Login to your account"/>
<img style="margin-bottom:15px;" src="/static/onenote_import_step_3.png" alt="Login to your account"/>
4. Please wait while all your notes are imported.
<img style="margin-bottom:15px;" src="../static/onenote_import_step_4.png" alt="Please wait while all your notes are imported."/>
<img style="margin-bottom:15px;" src="/static/onenote_import_step_4.png" alt="Please wait while all your notes are imported."/>
4. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
5. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,18 +2,19 @@
label: Plain text files
order: 900
---
# How do I import notes from plain text files?
To import plain text files to notesnook go to Notesnook Importer on your PC/Laptop.
1. From the list of formats to import, select "Plain Text".
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_1.png" alt="From the list of formats to import, select Plain Text."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_1.png" alt="From the list of formats to import, select Plain Text."/>
2. Drop your text files or click anywhere inside the box to browse and select your text files.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_2.png" alt="From the list of formats to import, select Plain Text."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_2.png" alt="From the list of formats to import, select Plain Text."/>
3. Click on import files button on bottom right corner to start importing files
4. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="From the list of formats to import, select Plain Text."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="From the list of formats to import, select Plain Text."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,28 +2,29 @@
label: Simplenote
order: 100
---
# How to import notes from Simplenote notes app?
The following steps will help you import your notes from Simplenote easily.
1. Open Simplenote app on Desktop or Login to [https://app.simplenote.com](https://app.simplenote.com).
2. Open sidebar and click on Settings.
<img style="margin-bottom:15px;" src="../static/simplenote_import_step_1.png" alt="Open sidebar and click on Settings."/>
<img style="margin-bottom:15px;" src="/static/simplenote_import_step_1.png" alt="Open sidebar and click on Settings."/>
3. Go to `Tools` tab in Settings
<img style="margin-bottom:15px;" src="../static/simplenote_import_step_2.png" alt="Go to Tools tab"/>
<img style="margin-bottom:15px;" src="/static/simplenote_import_step_2.png" alt="Go to Tools tab"/>
4. Click on `Export notes` to download your notes as a .zip file.
5. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Simplenote` from list of apps.
<img style="margin-bottom:15px;" src="../static/simplenote_import_step_3.png" alt="Go to [Notesnook Importer](https://importer.notesnook.com) and select `Simplenote` from list of apps."/>
<img style="margin-bottom:15px;" src="/static/simplenote_import_step_3.png" alt="Go to [Notesnook Importer](https://importer.notesnook.com) and select `Simplenote` from list of apps."/>
6. Drop the .zip backup file you exported earlier from Simplenote in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="../static/simplenote_import_step_4.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
<img style="margin-bottom:15px;" src="/static/simplenote_import_step_4.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
7. Click on `Import 1 file` button to start importing.
8. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -2,31 +2,29 @@
label: Standard Notes
order: 300
---
# How do I import notes from Standard Notes?
The following steps will help you import your notes from Standard notes easily.
1. Open Standard Notes app on Desktop or visit [https://app.standardnotes.org](https://app.standardnotes.org) and Login to your account.
2. Click on `Account` on bottom left corner
<img style="margin-bottom:15px;" src="../static/snnotes_import_step_1.png" alt="Click on `Account` on bottom left corner"/>
<img style="margin-bottom:15px;" src="/static/snnotes_import_step_1.png" alt="Click on `Account` on bottom left corner"/>
2. Scroll down to `Data backups` section and choose backup type `Decrypted`.
<img style="margin-bottom:15px;" src="../static/snnotes_import_step_2.png" alt="Scroll down to `Data backups` section and choose backup type Decrypted."/>
3. Scroll down to `Data backups` section and choose backup type `Decrypted`.
<img style="margin-bottom:15px;" src="/static/snnotes_import_step_2.png" alt="Scroll down to `Data backups` section and choose backup type Decrypted."/>
3. Click on `Download backup` to download your backup file. It will be .zip file.
4. Click on `Download backup` to download your backup file. It will be .zip file.
4. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Standard Notes` from list of apps.
<img style="margin-bottom:15px;" src="../static/snnotes_import_step_3.png" alt="Go to https://importer.notesnook.com and select Standard Notes from list of apps."/>
5. Go to [Notesnook Importer](https://importer.notesnook.com) and select `Standard Notes` from list of apps.
<img style="margin-bottom:15px;" src="/static/snnotes_import_step_3.png" alt="Go to https://importer.notesnook.com and select Standard Notes from list of apps."/>
5. Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="../static/snnotes_import_step_4.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
6. Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup.
<img style="margin-bottom:15px;" src="/static/snnotes_import_step_4.png" alt="Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup."/>
6. Click on `Import 1 file` button to start importing.
7. Click on `Import 1 file` button to start importing.
7. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="../static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
8. Click on `Download .nnbackup` to download the file.
<img style="margin-bottom:15px;" src="/static/plain_text_import_step_3.png" alt="Click on `Download .nnbackup` to download the file."/>
After you have downloaded the `.nnbackup` file, go to Notesnook app and [restore backup](../backup-and-restore-notes-in-notesnook.md) file to get all your notes.

View File

@@ -9,20 +9,21 @@ Colors are a simple and fast way to organize your notes.
## Assign color to note
+++ Desktop/Web
1. Click on the `three dot more` button or right click on a note to open `Note properties` menu
2. Add note to the desired color
![](../static/color_note_desktop.png)
![](/static/color_note_desktop.png)
3. You can click on the color again to remove note from the color
+++ Mobile/Tablet
+++ Mobile/Tablet
1. Press the `three-dot more` button on right side on note to open `Note properties` sheet
<img style="width:300px;margin-bottom:15px" src="../static/color_note_step_1.jpg" alt="Click on the more button on right side of note."/>
<img style="width:300px;margin-bottom:15px" src="/static/color_note_step_1.jpg" alt="Click on the more button on right side of note."/>
2. Add note to the desired color
<img style="width:300px;margin-bottom:15px" src="../static/color_note_step_2.jpg" alt="Select the desired color from the Bottom Sheet Menu."/>
<img style="width:300px;margin-bottom:15px" src="/static/color_note_step_2.jpg" alt="Select the desired color from the Bottom Sheet Menu."/>
3. You can press on the color again to remove note from the color
+++
@@ -31,4 +32,4 @@ Colors are a simple and fast way to organize your notes.
A shortcut to notes of specific color appears on side menu by default. The shortcut will appear as long as there is at least one note in a color.
![](../static/color_pinned_side_desktop.png)
![](/static/color_pinned_side_desktop.png)

View File

@@ -1,25 +1,28 @@
---
label: Favorites
---
# How can I add notes to favorites?
While you organize your notes with all different types of notebooks, tags and colors, favorites give you quick access to the notes that are most important to you in one tap.
## Add a note to favorites
+++ Desktop/Web
1. Righ click on a note or click on the three-dot more button to open `Note properties` menu
2. Toggle favorite
3. You can click again to remove note from favorites.
+++ Mobile/Tablet
1. Press the `three-dot more` button on the note to open `Note propreties` sheet
4. Press the `three-dot more` button on the note to open `Note propreties` sheet
<img style="width:300px;margin-bottom:15px" src="../static/color_note_step_1.jpg" alt="Click on the more button on right side of note."/>
<img style="width:300px;margin-bottom:15px" src="/static/color_note_step_1.jpg" alt="Click on the more button on right side of note."/>
2. Toggle favorite in the column.
<img style="width:300px;margin-bottom:15px" src="../static/favorite_note.jpg" alt="Toggle favorite in the column."/>
<img style="width:300px;margin-bottom:15px" src="/static/favorite_note.jpg" alt="Toggle favorite in the column."/>
4. You can press again on favorite to remove note from favorites
+++
Now if you go to the Favorites section from Side Menu, you will find your note there.
![](../static/favorites_page.png)
Now if you go to the Favorites section from Side Menu, you will find your note there.
![](/static/favorites_page.png)

View File

@@ -1,27 +0,0 @@
{
"input": ".",
"output": "public_html",
"branding": {
"title": "Notesnook",
"label": "Docs",
"colors": {
"label": {
"text": "#ffffff",
"background": "#00c853"
}
}
},
"exclude": ["*node_modules/", "*__generator__/"],
"favicon": "favicon.png",
"meta": {
"title": " | Notesnook Docs"
},
"edit": {
"repo": "https://github.com/streetwriters/notesnook",
"base": "docs"
},
"links": [],
"footer": {
"copyright": "&copy; Copyright {{ year }} [Streetwriters LLC](https://streetwriters.co/). All rights reserved."
}
}

22
docs/retype.yml Normal file
View File

@@ -0,0 +1,22 @@
input: .
output: public_html
url: https://docs.notesnook.com
branding:
title: Notesnook
label: Docs
colors:
label:
text: "#ffffff"
background: "#00C853"
exclude:
- "*node_modules/"
- "*__generator__/"
favicon: favicon.png
meta:
title: " | Notesnook Docs"
edit:
repo: "https://github.com/streetwriters/notesnook"
base: "docs"
footer:
copyright: "&copy; Copyright {{ year }} [Streetwriters LLC](https://streetwriters.co/). All rights reserved."

View File

@@ -1,3 +0,0 @@
icon: typography
label: Rich text editing
order: 950

View File

@@ -24,9 +24,9 @@ We are really exciting about what is coming to Notesnook by the end of Q2 2021.
## `Q3 2021`
- [ ] **Encrypted file attachements and data compression**
- [x] **Encrypted file attachements and data compression**
- [ ] **Stylus & Drawing Support** to take notes by drawing on the screen. We will be adding a dedicated editor where you can draw and take notes.
- [ ] **Widgets on Android & iOS** - Initially we are working on adding a Quick Note widget to add notes without opening app. [WIP]
- [x] **Widgets on Android & iOS** - Initially we are working on adding a Quick Note widget to add notes without opening app. [WIP]
- [ ] **Reminders**
- [ ] **Global Discord-like search** with advanced filtering
- [ ] Complete app documentation

13
docs/versionhistory.md Normal file
View File

@@ -0,0 +1,13 @@
---
icon: history
label: Version History
order: -5
---
To improve the overall reliability of Notesnook we have introduced version history of notes in v1.7.0 of desktop and mobile apps. Version history is enabled by default for all your notes including notes in vault.
## How it works
When you create a new note or open an existing note in the editor, a session is generated from the note opened in editor. All the changes made to the note are stored in that session. So if you open a note and edit it at 10 different times during the day, 10 versions of note history are generated and stored.
## Is Note history synced to all my devices?
No, at the moment we have decided to keep note version history local only and it is not synced. Hence if you logout from your account, note version history will be deleted.

31
notesnook.code-workspace Normal file
View File

@@ -0,0 +1,31 @@
{
"folders": [
{
"name": "✨ notesnook",
"path": "."
},
{
"name": "🚀 @notesnook/importer-web",
"path": "apps/importer"
},
{
"name": "📦 @notesnook/crypto",
"path": "packages/crypto"
},
{
"name": "📦 @notesnook/enex",
"path": "packages/enex"
},
{
"name": "📦 @notesnook/importer",
"path": "packages/importer"
},
{
"name": "📦 @streetwriters/tinymce-plugins",
"path": "packages/tinymce-plugins"
}
],
"settings": {
"git.ignoreLimitWarning": true
}
}

56575
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "notesnook",
"version": "1.0.0",
"description": "",
"main": "index.js",
"private": true,
"directories": {
"doc": "docs"
},
"repository": {
"type": "git",
"url": "git+https://github.com/streetwriters/notesnook.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/streetwriters/notesnook/issues"
},
"homepage": "https://github.com/streetwriters/notesnook#readme",
"devDependencies": {
"@changesets/cli": "^2.18.1",
"turbo": "^1.0.19"
},
"workspaces": [
"packages/*",
"apps/*"
],
"turbo": {
"baseBranch": "origin/main",
"pipeline": {
"build": {
"dependsOn": [
"^build"
]
}
}
}
}

View File

@@ -0,0 +1,5 @@
*
!dist/**/**/*
!package.json
!README.md

124
packages/crypto/index.ts Normal file
View File

@@ -0,0 +1,124 @@
import { ready } from "libsodium-wrappers";
import Decryption from "./src/decryption";
import Encryption from "./src/encryption";
import { INNCrypto, IStreamable } from "./src/interfaces";
import KeyUtils from "./src/keyutils";
import Password from "./src/password";
import {
Cipher,
EncryptionKey,
OutputFormat,
Plaintext,
SerializedKey,
Chunk,
} from "./src/types";
export class NNCrypto implements INNCrypto {
private isReady: boolean = false;
private async init() {
if (this.isReady) return;
await ready;
this.isReady = true;
}
async encrypt(
key: SerializedKey,
plaintext: Plaintext,
outputFormat: OutputFormat = "uint8array"
): Promise<Cipher> {
await this.init();
return Encryption.encrypt(key, plaintext, outputFormat);
}
async decrypt(
key: SerializedKey,
cipherData: Cipher,
outputFormat: OutputFormat = "text"
): Promise<Plaintext> {
await this.init();
return Decryption.decrypt(key, cipherData, outputFormat);
}
async hash(password: string, salt: string): Promise<string> {
await this.init();
return Password.hash(password, salt);
}
async deriveKey(password: string, salt?: string): Promise<EncryptionKey> {
await this.init();
return KeyUtils.deriveKey(password, salt);
}
async exportKey(password: string, salt?: string): Promise<SerializedKey> {
await this.init();
return KeyUtils.exportKey(password, salt);
}
async createEncryptionStream(
key: SerializedKey,
stream: IStreamable
): Promise<string> {
await this.init();
const encryptionStream = Encryption.createStream(key);
while (true) {
const chunk = await stream.read();
if (!chunk) break;
const { data, final } = chunk;
if (!data) break;
const encryptedChunk: Chunk = {
data: encryptionStream.write(data, final),
final,
};
await stream.write(encryptedChunk);
if (final) break;
}
return encryptionStream.header;
}
async createDecryptionStream(
iv: string,
key: SerializedKey,
stream: IStreamable
) {
await this.init();
const decryptionStream = Decryption.createStream(iv, key);
while (true) {
const chunk = await stream.read();
if (!chunk) break;
const { data, final } = chunk;
if (!data) break;
const decryptedChunk: Chunk = {
data: decryptionStream.read(data),
final,
};
await stream.write(decryptedChunk);
if (final) break;
}
}
async encryptStream(
key: SerializedKey,
stream: IStreamable,
_streamId?: string
): Promise<string> {
await this.init();
return await this.createEncryptionStream(key, stream);
}
async decryptStream(
key: SerializedKey,
iv: string,
stream: IStreamable,
_streamId?: string
): Promise<void> {
await this.init();
await this.createDecryptionStream(iv, key, stream);
}
}

71
packages/crypto/package-lock.json generated Normal file
View File

@@ -0,0 +1,71 @@
{
"name": "@notesnook/crypto",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/crypto",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"libsodium-wrappers": "^0.7.9"
},
"devDependencies": {
"@types/libsodium-wrappers": "^0.7.9"
}
},
"../streamablefs": {
"version": "1.0.0",
"extraneous": true,
"license": "ISC",
"dependencies": {
"localforage": "^1.10.0"
},
"devDependencies": {
"@types/localforage": "^0.0.34",
"typescript": "^4.4.3"
}
},
"node_modules/@types/libsodium-wrappers": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
"integrity": "sha512-LisgKLlYQk19baQwjkBZZXdJL0KbeTpdEnrAfz5hQACbklCY0gVFnsKUyjfNWF1UQsCSjw93Sj5jSbiO8RPfdw==",
"dev": true
},
"node_modules/libsodium": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.9.tgz",
"integrity": "sha512-gfeADtR4D/CM0oRUviKBViMGXZDgnFdMKMzHsvBdqLBHd9ySi6EtYnmuhHVDDYgYpAO8eU8hEY+F8vIUAPh08A=="
},
"node_modules/libsodium-wrappers": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
"integrity": "sha512-9HaAeBGk1nKTRFRHkt7nzxqCvnkWTjn1pdjKgcUnZxj0FyOP4CnhgFhMdrFfgNsukijBGyBLpP2m2uKT1vuWhQ==",
"dependencies": {
"libsodium": "^0.7.0"
}
}
},
"dependencies": {
"@types/libsodium-wrappers": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
"integrity": "sha512-LisgKLlYQk19baQwjkBZZXdJL0KbeTpdEnrAfz5hQACbklCY0gVFnsKUyjfNWF1UQsCSjw93Sj5jSbiO8RPfdw==",
"dev": true
},
"libsodium": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.9.tgz",
"integrity": "sha512-gfeADtR4D/CM0oRUviKBViMGXZDgnFdMKMzHsvBdqLBHd9ySi6EtYnmuhHVDDYgYpAO8eU8hEY+F8vIUAPh08A=="
},
"libsodium-wrappers": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
"integrity": "sha512-9HaAeBGk1nKTRFRHkt7nzxqCvnkWTjn1pdjKgcUnZxj0FyOP4CnhgFhMdrFfgNsukijBGyBLpP2m2uKT1vuWhQ==",
"requires": {
"libsodium": "^0.7.0"
}
}
}
}

View File

@@ -0,0 +1,25 @@
{
"name": "@notesnook/crypto",
"private": false,
"description": "An easy to use wrapper around libsodium exposing essential cryptographic methods. Currently only Web is supported.",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc --declaration --outDir ./dist"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"libsodium-wrappers": "^0.7.9"
},
"devDependencies": {
"@types/libsodium-wrappers": "^0.7.9"
},
"repository": {
"type": "git",
"url": "https://github.com/streetwriters/notesnook.git",
"directory": "packages/crypto"
}
}

View File

@@ -0,0 +1,94 @@
import {
crypto_aead_xchacha20poly1305_ietf_decrypt,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_secretstream_xchacha20poly1305_pull,
to_base64,
from_base64,
base64_variants,
StateAddress,
to_string,
from_hex,
} from "libsodium-wrappers";
import KeyUtils from "./keyutils";
import {
Cipher,
EncryptionKey,
OutputFormat,
Plaintext,
SerializedKey,
} from "./types";
export default class Decryption {
private static transformInput(cipherData: Cipher): Uint8Array {
let input: Uint8Array | null = null;
if (
typeof cipherData.cipher === "string" &&
cipherData.format === "base64"
) {
input = from_base64(
cipherData.cipher,
base64_variants.URLSAFE_NO_PADDING
);
} else if (
typeof cipherData.cipher === "string" &&
cipherData.format === "hex"
) {
input = from_hex(cipherData.cipher);
} else if (cipherData.cipher instanceof Uint8Array) {
input = cipherData.cipher;
}
if (!input) throw new Error("Data cannot be null.");
return input;
}
static decrypt(
key: SerializedKey,
cipherData: Cipher,
outputFormat: OutputFormat = "text"
): Plaintext {
if (!key.salt && cipherData.salt) key.salt = cipherData.salt;
const encryptionKey = KeyUtils.transform(key);
const input = this.transformInput(cipherData);
const plaintext = crypto_aead_xchacha20poly1305_ietf_decrypt(
null,
input,
null,
from_base64(cipherData.iv),
encryptionKey.key
);
return {
format: outputFormat,
data:
outputFormat === "base64"
? to_base64(plaintext, base64_variants.ORIGINAL)
: outputFormat === "text"
? to_string(plaintext)
: plaintext,
};
}
static createStream(header: string, key: SerializedKey): DecryptionStream {
return new DecryptionStream(header, KeyUtils.transform(key));
}
}
class DecryptionStream {
state: StateAddress;
constructor(header: string, key: EncryptionKey) {
this.state = crypto_secretstream_xchacha20poly1305_init_pull(
from_base64(header),
key.key
);
}
read(chunk: Uint8Array): Uint8Array {
const { message } = crypto_secretstream_xchacha20poly1305_pull(
this.state,
chunk,
null
);
return message;
}
}

View File

@@ -0,0 +1,105 @@
import {
crypto_aead_xchacha20poly1305_ietf_encrypt,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_push,
randombytes_buf,
crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
crypto_secretstream_xchacha20poly1305_TAG_FINAL,
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE,
to_base64,
from_base64,
base64_variants,
StateAddress,
} from "libsodium-wrappers";
import KeyUtils from "./keyutils";
import {
Cipher,
EncryptionKey,
OutputFormat,
Plaintext,
SerializedKey,
} from "./types";
const encoder = new TextEncoder();
export default class Encryption {
private static transformInput(plaintext: Plaintext): Uint8Array {
let data: Uint8Array | null = null;
if (typeof plaintext.data === "string" && plaintext.format === "base64") {
data = from_base64(plaintext.data, base64_variants.ORIGINAL);
} else if (typeof plaintext.data === "string") {
data = encoder.encode(plaintext.data);
} else if (plaintext.data instanceof Uint8Array) {
data = plaintext.data;
}
if (!data) throw new Error("Data cannot be null.");
return data;
}
static encrypt(
key: SerializedKey,
plaintext: Plaintext,
outputFormat: OutputFormat = "uint8array"
): Cipher {
const encryptionKey = KeyUtils.transform(key);
const data = this.transformInput(plaintext);
const nonce = randombytes_buf(crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
const cipher: string | Uint8Array =
crypto_aead_xchacha20poly1305_ietf_encrypt(
data,
null,
null,
nonce,
encryptionKey.key
);
let output: string | Uint8Array = cipher;
if (outputFormat === "base64") {
output = to_base64(cipher, base64_variants.URLSAFE_NO_PADDING);
}
const iv = to_base64(nonce);
return {
format: outputFormat,
alg: getAlgorithm(base64_variants.URLSAFE_NO_PADDING),
cipher: output,
iv,
salt: encryptionKey.salt,
length: data.length,
};
}
static createStream(key: SerializedKey): EncryptionStream {
return new EncryptionStream(KeyUtils.transform(key));
}
}
class EncryptionStream {
state: StateAddress;
header: string;
constructor(key: EncryptionKey) {
const { state, header } = crypto_secretstream_xchacha20poly1305_init_push(
key.key,
"base64"
);
this.state = state;
this.header = header;
}
write(chunk: Uint8Array, final?: boolean): Uint8Array {
return crypto_secretstream_xchacha20poly1305_push(
this.state,
chunk,
null,
final
? crypto_secretstream_xchacha20poly1305_TAG_FINAL
: crypto_secretstream_xchacha20poly1305_TAG_MESSAGE
);
}
}
function getAlgorithm(base64Variant: base64_variants) {
//Template: encryptionAlgorithm-kdfAlgorithm-base64variant
return `xcha-argon2i13-${base64Variant}`;
}

View File

@@ -0,0 +1,46 @@
import {
Cipher,
EncryptionKey,
OutputFormat,
Plaintext,
SerializedKey,
Chunk,
} from "./types";
export interface IStreamable {
read(): Promise<Chunk | undefined>;
write(chunk: Chunk | undefined): Promise<void>;
}
export interface INNCrypto {
encrypt(
key: SerializedKey,
plaintext: Plaintext,
outputFormat?: OutputFormat
): Promise<Cipher>;
decrypt(
key: SerializedKey,
cipherData: Cipher,
outputFormat?: OutputFormat
): Promise<Plaintext>;
hash(password: string, salt: string): Promise<string>;
deriveKey(password: string, salt?: string): Promise<EncryptionKey>;
exportKey(password: string, salt?: string): Promise<SerializedKey>;
encryptStream(
key: SerializedKey,
stream: IStreamable,
streamId?: string
): Promise<string>;
decryptStream(
key: SerializedKey,
iv: string,
stream: IStreamable,
streamId?: string
): Promise<void>;
}

View File

@@ -0,0 +1,57 @@
import {
from_base64,
to_base64,
randombytes_buf,
crypto_pwhash,
crypto_pwhash_SALTBYTES,
crypto_pwhash_ALG_ARGON2I13,
crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
} from "libsodium-wrappers";
import { EncryptionKey, SerializedKey } from "./types";
export default class KeyUtils {
static deriveKey(password: string, salt?: string): EncryptionKey {
let saltBytes: Uint8Array;
if (!salt) saltBytes = randombytes_buf(crypto_pwhash_SALTBYTES);
else {
saltBytes = from_base64(salt);
}
if (!saltBytes)
throw new Error("Could not generate bytes from the given salt.");
const key = crypto_pwhash(
crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
password,
saltBytes,
3, // operations limit
1024 * 1024 * 8, // memory limit (8MB)
crypto_pwhash_ALG_ARGON2I13
);
return {
key,
salt: typeof salt === "string" ? salt : to_base64(saltBytes),
};
}
static exportKey(password: string, salt?: string): SerializedKey {
const { key, salt: keySalt } = this.deriveKey(password, salt);
return { key: to_base64(key), salt: keySalt };
}
/**
* Takes in either a password or a serialized encryption key
* and spits out a key that can be directly used for encryption/decryption.
* @param input
*/
static transform(input: SerializedKey): EncryptionKey {
if ("password" in input && !!input.password) {
const { password, salt } = input;
return this.deriveKey(password, salt);
} else if ("key" in input && !!input.salt && !!input.key) {
return { key: from_base64(input.key), salt: input.salt };
}
throw new Error("Invalid input.");
}
}

View File

@@ -0,0 +1,22 @@
import {
crypto_generichash,
crypto_pwhash,
crypto_pwhash_ALG_ARGON2ID13,
crypto_pwhash_SALTBYTES,
} from "libsodium-wrappers";
export default class Password {
static hash(password: string, salt: string): string {
const saltBytes = crypto_generichash(crypto_pwhash_SALTBYTES, salt);
const hash = crypto_pwhash(
32,
password,
saltBytes,
3, // operations limit
1024 * 1024 * 64, // memory limit (8MB)
crypto_pwhash_ALG_ARGON2ID13,
"base64"
);
return hash;
}
}

View File

@@ -0,0 +1,33 @@
import { StringOutputFormat, Uint8ArrayOutputFormat } from "libsodium-wrappers";
export type OutputFormat = Uint8ArrayOutputFormat | StringOutputFormat;
export type Cipher = {
format: OutputFormat;
alg: string;
cipher: string | Uint8Array;
iv: string;
salt: string;
length: number;
};
export type Plaintext = {
format: OutputFormat;
data: string | Uint8Array;
};
export type SerializedKey = {
password?: string;
key?: string;
salt?: string;
};
export type EncryptionKey = {
key: Uint8Array;
salt: string;
};
export type Chunk = {
data: Uint8Array;
final: boolean;
};

View File

@@ -0,0 +1,104 @@
{
"compilerOptions": {
"outDir": "./dist",
"declaration": true,
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "commonjs" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["src/", "index.ts"]
}

3
packages/enex/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
.nyc_output
dist

5
packages/enex/.npmignore Normal file
View File

@@ -0,0 +1,5 @@
*
!dist/**/**/*
!package.json
!README.md

3
packages/enex/README.md Normal file
View File

@@ -0,0 +1,3 @@
# @notesnook/enex
A fully tested type-safe Evernote .enex parser used in Notesnook Importer.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">
<en-export export-date="20201025T193452Z" application="Evernote" version="Evernote Mac 7.14 (458244)">
<note><title>ExampleNoteInSameDir</title><content><![CDATA[<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>NoteA</div></en-note>]]></content><created>20201025T193016Z</created><updated>20201025T193424Z</updated><note-attributes><latitude>46.7625732421875</latitude><longitude>19.59793272236583</longitude><altitude>114.9751129150391</altitude><author>akos</author><source>desktop.mac</source><reminder-order>0</reminder-order></note-attributes></note>
</en-export>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">
<en-export export-date="20201025T193510Z" application="Evernote" version="Evernote Mac 7.14 (458244)">
<note><title>ExampleNoteInSameDir</title><content><![CDATA[<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd"><en-note><div>NoteB</div></en-note>]]></content><created>20201025T193016Z</created><updated>20201025T193458Z</updated><note-attributes><latitude>46.7625732421875</latitude><longitude>19.59793272236583</longitude><altitude>114.9751129150391</altitude><author>akos</author><source>desktop.mac</source><reminder-order>0</reminder-order></note-attributes></note>
</en-export>

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