* Inspiring Adversary ** evernote.com ** Google Keep ** bear.app ** collectednotes.com ** joplinapp.org ** github.com/mozilla/notes ** wereturtle.github.io/ghostwriter ** milanote.com ** cloverapp.co ** nat.app/note-taking ** gekri.com ** www.zotero.org ** usejournal.com ** getpolarized.io ** standardnotes.com ** simplenote.com ** github.com/zadam/trilium ** github.com/logseq/logseq ** github.com/OmGodse/Notally ** github.com/twitter/TwitterTextEditor ** www.serenity.re/en/notes ** skiff.com ** notesnook.com ** anytype.io ** grugnotes.com ** github.com/flxzt/rnote ** affine.pro, github.com/toeverything/AFFiNE ** github.com/maltaisn/another-notes-app ** getupnote.com ** noteplan.co * Same Name ** jusnote.com - The most powerful software for managing the legal practice ** justnotepad.com ** justnoteit.com ** play.google.com/store/apps/details?id=enterprise.velle.justnote ** play.google.com/store/apps/details?id=app.pnrnts.notes.notes ** github.com/pavlo-zin/JustNote ** github.com/tseleski/JustNote ** www.macupdate.com/app/mac/33266/justnotes * Requirements ** simple, fast, intuitive - quick notes VS in-depth essays - focus mode - advanced markup options - dark mode, themes, fonts ** sync ** export ** share - direct url to the note, to other's note? another specific view? - iOS, Android extensions? - Chrome, Firefox extensions? ** popup and back ** fast - while loading data from server, new note button should be clickable and can add a new note right away ** lists ** tags ** Live demo - No need, super easy to try, no setup * POC ** domain name - http://justnote.cc - http://www.justnote.cc - https://justnote.cc <-- choose this one - https://www.justnote.cc ** Consistent in name - Justnote ** fonts - Atkinson Hyperlegible Font: brailleinstitute.org/freefont + Might not enough. There only regular and bold - Inter <-- choose this one ** All Notes VS My Notes - Notebooks? Lists? - My Notes, Archive, Trash, <-- choose this one ** supported screens - 5 screens: desktop, tablet:portrait, tablet:landscape, mobile:portrait, mobile:landscape - breakpoint at lg - Sidebar, Note list, Note editor + should be able to adjust width? - Fixed topbar, Fixed bottombar ** Flow *** Sign up / Sign in *** Create a new note *** list notes *** Open a note *** Edit/Update/Save a note *** Move a note: archive, remove, restore, move to *** Delete a note: permanently delete *** Change listname *** Create a new listname <-- in Settings *** Rename/Delete a listname <-- in Settings *** Bulk edit: archive, remove, restore, move to, delete *** Profile: settings, support, sign out *** Sync indicator: syncing, new update, *** StatusPopup *** Search *** Delete old notes in trash, export data, delete all data ** url hash - Also use url for popup and confirm delete! - url: https://justnote.cc + /, /about, /privacy, /terms, /support + /#?u=&n=&p=&cd=true ** routers *** web - No need react-router, use framer-motion *** native - No need react-navigation, use animated ** components *** sidebar - show/hide sidebar, need a button to click to show! *** note list *** editor *** search - need to add top padding dynamically? *** split screens - github.com/tomkp/react-split-pane - github.com/brucelin0325/react-native-resizable-flex-panes - github.com/STRML/react-grid-layout ** z-index - 0: note list, note - 10: search popup - 20: top bar, bottom bar - 30: popup - 40: setting popup - 50: confirm delete ** loading *** web *** native ** offline and sync in mobile app *** foundings - versioning/conflict/merge with file name! - delete need to keep all files! - fpath: notes///index.json - fname: <4 random chars>-parents - delete: add new one w/o content and update old one w/o content - sqlite on mobile *** storage on mobile - github.com/react-native-async-storage/async-storage + slower + on Android, need to set storage size limit - github.com/mrousavy/react-native-mmkv - github.com/ammarahm-ed/react-native-mmkv-storage + Faster + based on Tencent MMKV which should be ok + No need to set storage size limit + might need to trim storage size! + might have issues with JSI, Hermes and Proguard! ** data *** Gaia - /notes//_/index.json + title + body - /notes//_/[*.* i.e. jpg, png] *** noteId - id, parentIds, addedDT, updatedDT, isConflicted, conflictWith, listName, fpaths, *** Redux state - notes[listName][id] + parentIds + id + title + body + media: { : , ... } + addedDT + updatedDT ** text editor *** view mode vs edit mode *** file format! - web vs native *** inline image *** how and when to save *** libraries **** Quill - github.com/quilljs/quill, github.com/imnapo/react-native-cn-quill - Need to upload an image to server and use tag? + No, can use data image encoding but the file will be large + Need to manually extract from a note file? - Need to install plugin to resize an image - There's a bug on editing a very long article and no fix? - Production version is very old and no promise on newer version, dead project? - BSD license **** TinyMCE - github.com/tinymce/tinymce, github.com/rmccue/react-native-tinymce - High development activities - there are paid plans - support insert a table and resize an image - require to show their name&logo as attribution! - Use webview on react-native, bad for performance? - Obscure js code to prevent malicious hackers? - there's an option to upload an image and have data URL? - GNU LGPL license and require attribution **** Trix - github.com/basecamp/trix, github.com/vitalyliber/react-native-trix - need to use WebView on react-native - MIT license **** Slate - github.com/ianstormtaylor/slate - Not support mobile browser for now, in development - Need to use WebView on react-native **** DraftJs - draftjs.org - Not officially support mobile browser, there're known issues - Need to use WebView on react-native **** Wordpress Gutenberg - github.com/WordPress/gutenberg, github.com/wordpress-mobile/gutenberg-mobile - This's not just a text editor, it's a block editor for making a web page or a blog. Maybe this's too much? - React native library - GNU GPL license **** CKEditor - github.com/ckeditor/ckeditor5-react, github.com/ssg-luke/react-native-ckeditor5, github.com/mzupek/react-native-ckeditor5 - GNU GPL license - well suport on mobile browser - Need to use WebView on react-native * MVP * Fully Fledged * Implementation ** Web steps - yarn create react-app justnotecc --template cra-template-pwa - yarn add tailwindcss postcss autoprefixer - yarn add @tailwindcss/forms @tailwindcss/typography @tailwindcss/aspect-ratio @tailwindcss/line-clamp - npx tailwindcss init -p - yarn add redux react-redux redux-loop reselect - Fix dev server crash because of Emacs temp/lock file + github.com/facebook/create-react-app/issues/9056#issuecomment-744168146 + stackoverflow.com/questions/62567370/reactjs-local-server-crashes-after-editing-file-in-emacs-even-without-saving/62571200#62571200 - Favicon + cd public + convert logo16.png logo32.png logo48.png logo64.png favicon.ico - Font + Config in tailwind.config.js + Add font-face in layer: base in tailwind.css - yarn add @stacks/auth @stacks/storage @stacks/wallet-sdk @stacks/connect @stacks/encryption - yarn add url-parse - yarn add framer-motion - yarn add @welldone-software/why-did-you-render - yarn add file-saver - yarn add @ckeditor/ckeditor5-react - yarn add file:../../../justnote-editor - yarn add @types/node @types/react @types/react-dom @types/jest @types/url-parse @types/file-saver - fix webpack 5 issue + yarn add react-app-rewired stream-browserify crypto-browserify assert util buffer process + create config-overrides.js + change scripts in packages.js + ref: stackoverflow.com/questions/70429654/webpack-5-errors-cannot-resolve-crypto-http-and-https-in-reactjs-proje, github.com/facebook/create-react-app/issues/11756, stackoverflow.com/questions/63729455/hosted-images-with-react-pdf/70441023#70441023 - yarn add @zip.js/zip.js - yarn add @wewatch/lexorank axios - yarn add tailwindcss-labeled-groups - yarn add idb-keyval - yarn add jest-diff queue - yarn add blueimp-load-image ** Server steps *** namecheap - use ALIAS for root domain - setup SPF, DKIM, and DMARC *** s3 - Set public and enable CORS *** cloudfront, lambda@edge, certificate manager, and namecheap - Create SSL certificate and verify at namecheap - Create cloudfront distribution - Create a lambda function named redirectUrl, comes with a role i.e. redirectUrl-role-xxxxx, need to add more policies to that role like a lot - At that role -> Trust relationships, edit that json to contain server: edgelambda.amazonaws.com - Back to the function page -> Designer -> Add trigger, select cloudfront -> deploy to Lambda@Edge, select the correct distribution and select Viewer request. - Set cloudfront url in namecheap - Set Response headers policy -> Managed SecurityHeadersPolicy + stackoverflow.com/a/72512670 + aws.amazon.com/blogs/networking-and-content-delivery/amazon-cloudfront-introduces-response-headers-policies *** aws-cli - create justnote-cli user in IAM with S3FullAccess and CloudFrontFullAccess - aws-cli supports multiple users/profiles, add in ~/.aws/config and ~/.aws/credentials - every command follows by --profile ** Native steps - npx @react-native-community/cli@latest init Justnotecc --pm npm - npm i redux@4.2.1 react-redux@8.1.3 redux-loop@6.2.0 reselect@4.1.8 - npm i react-native-svg - npm i -D react-native-svg-transformer + Update metro.config.js to work with .svg - npm i url-parse - npm i react-native-animated-spinkit - npm i react-native-safe-area-context - npm i react-native-keyboard-manager - npm i react-native-webview - npm i react-native-file-access - npm i react-native-mmkv-storage@0.4.4 + Add proguard rules + require iOS target to 11.0 - npm i https://github.com/stxapps/tailwind-rn#96848a8d2c2370e4f5e57a773ace172c4073157d - npm i 'https://gitpkg.now.sh/stxapps/blockstack-react-native/BlockstackSDK?3d5bcd6ea9a17f00c76be5913009f2c02f13b95f' - npm i @welldone-software/why-did-you-render -D - npm i react-native-iap @wewatch/lexorank axios - npm i https://github.com/stxapps/react-native-device-time-format#63f4a9158a91c391d67317a489ccfe8ec28a7c84 - npm i https://github.com/stxapps/react-native-html-to-pdf#77aed8df9caa3b48f7cf19933bc6d6576fe817ce - npm i react-native-document-picker react-native-share react-native-zip-archive - npm i htmlparser2 - npm i react-native-flag-secure - npm i jest-diff queue event-target-fallback - npm i @bam.tech/react-native-image-resizer - npm i react-native-default-preference - npm i https://github.com/stxapps/react-native-receive-sharing-intent#d1b4aa9140e0ad28e1a8403814125a733c92172c - npm i react-native-system-navigation-bar @vonovak/react-native-theme-control - npm uninstall typescript && npm i typescript@5.5.4 -D - Font + Create react-native.config.js + Run npx react-native-asset + medium.com/@mehrankhandev/ultimate-guide-to-use-custom-fonts-in-react-native-77fcdf859cf4 - Android + android/gradle/wrapper/gradle-wrapper.properties ~ set gradle version in zip fpath + android/build.gradle ~ set android gradle plugin version ~ set minSdk, targetSdk, compileSdk, buildTools version + gen upload keystore ~ keytool -genkeypair -v -keystore justnote-android-upload-key.keystore -alias justnote-android-upload-key -keyalg RSA -keysize 2048 -validity 10000 + android/gradle.properties ~ add variables for upload keystore ~ add more memory when build (stackoverflow.com/questions/56075455/expiring-daemon-because-jvm-heap-space-is-exhausted) + android/app/build.gradle ~ enableHermes: true ~ enableProguardInReleaseBuilds = true ~ add exclude fpaths in packagingOptions in android block ~ add upload keystore in signingConfigs in android block ~ add javaMaxHeapSize in android block + android/app/proguard-rules.pro ~ add proguard rules + android/app/src/main/AndroidManifest.xml ~ Add 2 intent filters: justnotecc:// and https://justnote.cc + android/app/src/main/res/values/strings.xml ~ app_name Justnote + android/app/src/main/res/mipmap-xxxx ~ ic_launcher - iOS + ios/Podfile ~ Add PromiseObjC and Blockstack dependencies ~ Change platform version + Xcode/Justnotecc/Project ~ set iOS Deployment Target + Xcode/Justnotecc/Targets ~ set Display Name, Bundle Id, Version, Build, Deployment Info ~ set team ~ Add justnotecc:// + Xcode/Justnotecc/Targets/Signing & Capabilities ~ Click + and double clicks Associated Domains ~ Add applinks:justnote.cc + Xcode/Images.xcassets ~ app icons + ios/Justnotecc/AppDelegate.m ~ Add source code + Select Justnotecc in left pane, new -> swift file and generate header binding ~ if doesn't work > ios/Justnotecc/Targets/Build Settings > Search Paths/Library Search Paths: both Debug and Release add "${SDKROOT}/usr/lib/swift" non-recursive (developer.apple.com/forums/thread/655438) + Targets -> Justnotecc -> Build Settings -> Packaging -> Product Name: Justnotecc + Targets -> Justnotecc -> Build Settings -> Build Options -> Always embed Swift standard libraries: $(inherited) + Right click on Save to Justnote in Xcode sidebar, convert to group, make sure not buildable folder - Setup Universal Link and App Link on server + Upload assetlinks.json to justnote.cc/.well-known/, *not .wellknown!* ~ assume debug.keystore unchanged: git update-index --assume-unchanged packages/mobile/android/app/debug.keystore ~ generate a new debug.keystore and don't publish to github ~ generate sha256 for debug.keystore, make sure these two keystores never be published (*if passowrd contains $, put single quote around!*) keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android keytool -list -v -keystore android/app/debug.keystore -alias androiddebugkey -storepass android -keypass android ~ *Need sha256 from Play Store Console* at Release Management > App signing > App signing certificate > SHA-256 certificate fingerprint (medium.com/@joeykaan/the-definitive-guide-to-app-links-eef50a4c26e9) + Upload apple-app-site-association to justnote.cc/.well-known, *not .wellknown and content type application/json!* - Share to Justnote + Install react-native-receive-sharing-intent and react-native-default-preference + In android/app/src/main/AndroidManifest.xml, add ShareActivity + Create ShareActivity.java file, update values in String and Style + Add AppRegistry in mobile/index.js, Create share.js file + Listen to MainActivity's onResume and onPause ~ Update MainActivity, use DeviceEventEmitter to emit and listen to custom events ~ Not add appStateChange in init, add in Main.js instead + File -> New -> Target -> Share Extension ~ Save to Justnote, Swift ~ Check iOS target the same as main app + In Info.plist under Save To Justnote ~ NSExtension -> NSExtensionAttributes -> NSExtensionActivationRule -> NSExtensionActivationSupportsText -> true + Add App groups from targets: Justnotecc and Save to Justnote -> Signing & Capabilities ~ group.justnotecc.share + Add the dependency in Podfile with target 'Save to Justnote' + Add fonts to Save to Justnote ~ Xcode's sidebar -> Resources, select all fonts ~ Xcode's rightbar -> Target Membership, select Save to Justnote ~ Save to Justnote -> Info.plist, add Fonts provided by application + Add PrivacyInfo.xcprivacy * test cases - web, mobile - PC, laptop, tablet, phone - features + Landing, About, Terms, Privacy, Support + Sign up, Sign in + Main, ColsPanel, NavPanel, Sidebar, RightPanel + List notes, fetch more + New note, edit note, move note, delete note + Bulk edit: move notes, permanently delete notes + Retry add, edit, move, delete notes + Search + Sync, Conflict notes + List list names, change list name + New list name, edit list name, move list name, delete list name + Popups: ConfirmDelete, ConfirmDiscard, AlertRotate, MoveTo, ListMenu, Profile + Settings: account, subscription, data, lists, misc, about, Info: purchases + Conflict settings + Pin, unpin, move pin + WHT_MODE, BLK_MODE + Unsaved notes * servers ** test server - https://d2kp6vvq64w651.cloudfront.net ** prod - https://justnote.cc * ckeditor ** repo - Before upgrade + copy all changing files + replace all changing files including build dir ~ revert back _package.json to package.json ~ replace ckeditor5-build-decoupled-document with the one in tmp - merge from upstream/stable to origin/stable + git pull upstream stable + git push origin stable - merge from stable to justnote + git co justnote + git merge stable + git push origin justnote - Copy ckeditor5-build-decoupled-document in tmp for next time - apply change + change package.json to _package.json + edit packages/ckeditor5-build-decoupled-document/package.json + edit packages/ckeditor5-build-decoupled-document/src/ckeditor.js + add packages/ckeditor5-build-decoupled-document/src/objecturluploadadapter.js + run patch.js * Expo ** install - npx create-expo-app --template tabs - npx expo install expo-dev-client -- --save-dev - npm i file:../../../sdrive-hub-sdk/blockstack-react-native/react-native-blockstack-0.1.1.tgz + In the blockstack-react-native, run npm pack - npx expo install react-native-mmkv-storage@0.4.4 - npx expo install react-native-flag-secure - npm i react-redux redux redux-thunk reselect - npx expo install redux-devtools-expo-dev-plugin - npm i url-parse @wewatch/lexorank event-target-fallback queue - npm i htmlparser2@9.1.0 jest-diff@29.7.0 - npx expo install expo-share-intent - npx expo install react-native-file-access - npx expo install expo-navigation-bar - npx expo install expo-localization - npx expo install expo-iap - npx expo install expo-print - npx expo install react-native-zip-archive - npx expo install expo-document-picker - npx expo install expo-image-manipulator - npx expo install react-native-svg - npx expo install react-native-svg-transformer -- --save-dev - npx expo install react-native-webview - npx expo install react-native-keyboard-controller - npx expo install react-native-animated-spinkit - npx expo install react-native-share - npx expo install expo-build-properties - npx expo lint - npx expo install react-native-navigation-mode - npx expo install @stylistic/eslint-plugin -- --save-dev - npx expo install expo-system-ui - npx expo install react-native-edge-to-edge ** build - npx expo prebuild --clean - ios + open ios/Justnote.xcworkspace + choose Justnote on the right pane + targets: Justnote, on General: ~ update Version, App Category: Productivity, Display Name: Justnote + targets: Justnote, on Signing & Capabilities, add In-App Purchase + targets: Justnote, on Build Phases, add Target Dependency: SavetoJustnote + targets: SavetoJustnote, on General: ~ update Version, Miminum iOS, Display Name: Save to Justnote + targets: SavetoJustnote, on Signing & Capabilities, select team - android + copy justnote-android-upload-key.keystore to android/app + update keystore info in android/gradle.properties + update signingConfigs/release in android/app/build.gradle + change in buildTypes/release signingConfig to signingConfigs.release * Next ** Install - npx create-next-app@latest justnotecc + Choose typescript, tailwind and eslint + scripts dev - add --experimental-https --hostname - npm i redux react-redux redux-thunk reselect - npm i -D @tailwindcss/forms @tailwindcss/typography - npm i @stacks/auth@6.16.1 @stacks/encryption@6.16.1 @stacks/storage@6.16.1 @stacks/wallet-sdk@6.16.1 - npm i url-parse file-saver @wewatch/lexorank blueimp-load-image idb-keyval queue - npm i jest-diff@29.7.0 - npm i @zip.js/zip.js - npm i motion - npm i @serwist/next && npm i -D serwist - npm install -D @types/url-parse @types/file-saver - npm install -D @stylistic/eslint-plugin - npm i eslint-plugin-tailwindcss@beta -D - npm i @ckeditor/ckeditor5-react - npm i file:../../../justnote-editor ** Steps on AWS - same as brace.org