brace.org
Rama master · réplica de lectura del repositorio original.
* Inspiring Adversary
** raindrop.io
** linkwarden.app
** getpocket.com
** saved.io
** pinterest
** www.pagemarker.io
** getmemex.com
** www.linkpack.io
** larder.io
** notado.app
** www.linkace.org
** bmrk.cc
** bmrks.com
** bookmarkmanager.com
* Same Name
** brace.io
- www.studioanthonylane.com/Brace-io
** brace.ai
- Software to Revolutionize Mortgage Servicing
* poc
** subdomain names for tags
- set up a catch-all (wildcard) subdomain
https://www.namecheap.com/support/knowledgebase/article.aspx/597/2237/how-can-i-set-up-a-catchall-wildcard-subdomain/
- Use CNAME Record
CNAME Record - @ - parkingpage.namecheap.com. - 30 min
CNAME Record - * - parkingpage.namecheap.com. - 30 min
- If value is IP, change CNAME Record to A Record
- Can retrieve the whole url with js?
** static files + custom domain + wildcard SSL + CDN
*** google storage
- Works like CDN but not good as CDN
- No support https on custom domain
*** firebase
- No support wildcard SSL, only support https on subdomains, no more than 20 subdomains! and need to setup one by one!
*** google storage + google load balancer + google CDN
- Require load balancer to work with google CDN
- $18++ per month
*** google storage + cloudflare
- $5++ per month
*** render.com
- Too newly startup
*** netlify
- Limited usage. If exceed, $45++ per month
*** google app engine
- Need wildcard SSL from 3rd party i.e. from cloudflare $5 per month
- No CDN. Platform tries to distribute across its datacenters
- Should use standard enviroment for cost saving and scalability
*** aws cloudfront + s3
**** s3
- Create a new bucket with public access
- Upload files and folders in folder 'build' and make them all public
- At bucket properties, enable static website hosting
+ Index document: index.html
+ Error document: index.html
- access at http://brace-web.s3-website-us-east-1.amazonaws.com/
**** certificate manager
- Verify ownership of the domain name
+ Need to use AWS N.Virginia
+ At namecheap, host records -> CNAME Record
+ Name to Host but without domain name i.e _dea0a23bf1e683425e901e82d7c7e816.brace.to. -> _dea0a23bf1e683425e901e82d7c7e816
+ Value to Value as is
+ ref: https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html, https://stackoverflow.com/questions/51198472/cname-entry-not-working-on-namecheap-using-amazon-certificate-manager
**** cloudfront
- Origin domain name -> type yourself, from dropdown list is incorrect
- Viewer protocal policy -> Redirect HTTP -> HTTPS
- might not necessary
+ Default root object -> index.html
+ Error pages -> index.html
- At namecheap, CNAME Record on * and @ to cloudfront domain name i.e. df3eruy30b9uq.cloudfront.net
+ it will ended with dot because https://stackexchange.github.io/dnscontrol/why-the-dot
- *Invalidating files*
+ Try to use name versioning instead as more than 1000 requests needs to pay (https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html)
**** ref
- https://medium.com/@wolovim/deploying-create-react-app-to-s3-or-cloudfront-48dae4ce0af
- https://medium.com/dailyjs/a-guide-to-deploying-your-react-app-with-aws-s3-including-https-a-custom-domain-a-cdn-and-58245251f081
- https://benjamincongdon.me/blog/2017/06/13/How-to-Deploy-a-Secure-Static-Site-to-AWS-with-S3-and-CloudFront/#fnref:5
** web design
*** consideration
- color
- contrast
- white space
- visual hierarchy
- scale
- simplicity
- consistency
- responsiveness
*** guideline
**** layout, sizing, spacing, margin, padding, line-height
***** The 8-Point Grid with 4-point baseline system
- Set grid with 8px width and height
- soft grid
+ If size is divided by 8, margin or padding might not
+ Use 4pt system? too small?
- ref
+ https://builttoadapt.io/intro-to-the-8-point-grid-system-d2573cde8632
+ https://builttoadapt.io/8-point-grid-borders-and-layouts-e91eb97f5091
+ https://blog.prototypr.io/a-framework-for-creating-a-predictable-and-harmonious-spacing-system-8eee8aaf773c
+ https://spec.fm/specifics/8-pt-grid
+
**** font
**** color, shade, shaddow
***** refactoring ui
***** lyft color
- design.lyft.com/re-approaching-color-9e604ba22c88
*** design system
**** protocol.mozilla.org
**** material.io
**** primer.style
**** brand.uber.com
**** evergreen.segment.com
**** design.workday.com
**** thumbprint.design
**** ant.design
**** www.designsystems.com
**** orbit.kiwi
*** SVG tools
**** Inkscape
- For logo design, icon design, illustation design
- Free
*** UI/UX tools
**** Sketch
- $99 one time
- Only on Mac
**** Adobe XD
- Free with limited features
- On Mac and Windows only
**** Figma
***** founding
- For web UI and UX
- Free with limited features
- Web app
- Can use instead of Inkscape for simple logos, icons, illustrations
+ Better as no need to import/reimport after edit/update the logo/icon
- Make logos/icons components so that when change, apply to all linked. And can apply directly to linked item for specific change
- Components can not published with free plan, need to pay
- Styles and Components are published to team level, not project level
- As no shared components, need to do everything in 1 file! logo, illustrations, pages
- Do everything in 1 file, performance issue?
- In a file, can have several pages
***** workflow
- team -> project -> file -> page
- 1 file, 4 pages: design system, logo, illustrations, pages
- Create local styles and local components in design system page
+ color pallete
+ 2 font types: font-head, font-content
+ size
+ weight
+ leading, line height
+ h1-h6
- Create frames in pages like
+ landing_desktop_pattern1
+ landing_mobile_pattern1
+ landing_android_pattern1
+ landing_ios_pattern1
+ main_desktop_
+ main_mobile_
+ main_android_
+ main_ios_
*** Color tools
**** colors.co
**** colormind.io
*** Contrast tools
**** usecontrast.com
**** webaim.org/resources/contrastchecker
*** Font tools
**** fontsinuse.com
**** klim.co.nz
**** hanken.co
**** www.fontsquirrel.com
**** typewolf.com
*** Chrome extensions
- responsive-viewer: chrome.google.com/webstore/detail/responsive-viewer/inmopeiepgfljkpkidclfgbgbmfcennb
- PixelParallel: chrome.google.com/webstore/detail/pixelparallel-by-htmlburg/iffnoibnepbcloaaagchjonfplimpkob
- VisBug: chrome.google.com/webstore/detail/visbug/cdockenadnadldjbbgcallicgledbeoc
*** Free icons
- github.com/refactoringui/heroicons, www.heroicons.com/
- www.zondicons.com
- www.heropatterns.com
- iconscout.com
- icons8.com
- fontawesome.com
- useiconic.com
- streamlineicons.com
- github.com/tabler/tabler-icons
- github.com/twbs/icons
- systemuicons.com
- iconbuddy.com
*** Free illustrations
- undraw.co
- humaaans.com
*** Free images
- unsplash.com
- www.istockphoto.com
*** Inspiration
- land-book.com
- pages.xyz
- www.awwwards.com
- thefwa.com
*** starter kit
**** Predifined Tailwind CSS + Free templates
**** pdkit.co
**** antforfigma.com ($79)
**** setproduct.com ($86)
**** refactoring UI ($149)
**** tailwindui.com ($249)
** css system
*** bulma
- Good for use as is
*** tailwind
- Customizable
- Use with create_react_app
+ import './tailwind.css';
- ref
+ tailwindcss.com/
+ tailwindcomponents.com
+ tailwindtoolbox.com/
+ tailwindui.com
+ www.youtube.com/watch?v=J_7_mnFSLDg
+ github.com/aniftyco/awesome-tailwindcss
*** misc.
- debug.css
- cssstats.com
** single web app for every page
*** pages
- landing/home page
- list/delete/add/edit page
- add via url page
*** libraries
**** yarn
- yarn init
**** babel
- yarn add @babel/core @babel/cli @babel/preset-env @babel/preset-react --dev
- create .babelrc at the project root
**** webpack
- yarn add webpack webpack-cli webpack-dev-server style-loader css-loader babel-loader --dev
- create webpack.config.js at the project root
**** react
**** sass/scss + bulma
**** ref
- blog.usejournal.com/creating-a-react-app-from-scratch-f3c693b84658
*** starter-kits
**** create-react-app
** gaia & sync
*** founding
- some sync requires implementation on both client and server i.e. synceddb (github.com/paldepind/synceddb), pouchdb (pouchdb.com), turtleDB (turtle-db.github.io)
- manual sync is cumbersum
+ https://github.com/smebberson/array-sync - every time compare needs to load all items
+ keep timestamp at client and keep log files of changes at gaia, max log files might be 10, compare tiemstamps and apply changes, update changes to gaia (a log file) <- irony?
+ *easier with only add and delete?* use file names(MD5 of content + created dt + updated dt) for sync
+ load just file names to compare? order is important!
+ for bidirectional sync, how to know it's delete or add?
+ Too complicate, need CRDTs!
- if there are *thousands items*, first time sync would take long time
- IndexedDB and LocalStorage are temporary, not persistant
- Most promising would be PouchDB
+ Gaia is wrapped by DownLevel and PouchDB connects to by leveldb -> PouchDB will treat it as local database but actually underneath blockstack API is called
+ Create idb as local database, update to this one and sync to the above one
+ No as required CouchDB! (pouchdb.com/faq.html) for Multiversion concurrency control(MCC) and IndexedDB has a limit!
- Conflict-free Replicated Data Types (CRDTs)
+ might be too slow to download all change log and build final results
+ the list will keep growing with changes
+ ref: github.com/orbitdb/crdts, github.com/conclave-team/conclave
*** ref
- medium.com/@cody_84149/gaia-storage-with-leveldb-37112007e335
- hackernoon.com/building-conclave-a-decentralized-real-time-collaborative-text-editor-a6ab438fe79f
- hackernoon.com/turtledb-a-javascript-framework-for-building-offline-first-collaborative-web-apps-7183cd787163
** gaia & service worker & indexedDB & Cache API
*** cache in indexedDB for faster startup
- Check if there are items in indexedDB, if yes, show these first
- In the background (might not need service worker), connect to Gaia and load latest items
- if there is change, update UI with latest items
- Save ONLY latest items in indexedDB for fast startup only!
- Cache API might not suitable as the same request would return different response, except static files
- *no need* to do this manually because there is *stale-while-revalidate*
+ www.toptal.com/react-hooks/stale-while-revalidate
*** SWR for faster startup
- github.com/zeit/swr
- features
+ stale-while-revalidate
+ Focus Revalidation
+ Refetch on Interval
+ Scroll Position Recovery and Pagination
- check
+ can work with gaia? yes
+ pagination?
+ add/edit/delete apply to cache? force update? force refetch?
- alternative
+ react-query
*** background job for add/edit/delete and save results in indexedDB for error handling
- Save data in indexedDB first
- Connect to Gaia to update
- if succeed, clear indexedDB, if not retry
- Need to be a queue
- check
+ If add and then edit/delete while still connecting to Gaia?
+ If first error, how to handle next in the queue?
- should use library i.e. redux-offline
*** redux-offline for faster startup
-
*** redux-offline for add/edit/delete
- github.com/redux-offline/redux-offline
- can be used for faster startup too, no need SWR
-
*** require appropriate UI
- loading
- message
*** caveat
**** inconsistency in indexedDB / cache management
- when first visit
- when revisit
- when refresh
- when add/edit/delete items
- when load more
- when scroll down/scroll up
*** tools
**** workbox
**** idb
- www.npmjs.com/package/idb
**** dexie.org
- Wrapper for IndexedDB
*** ref
- developers.google.com/web
- serviceworke.rs
** for each gaia server, one file per one link. performance issue?
*** questions
- each file, json data: url, title, image, web_favicon, just_web_name, beautifed_flag, uuid/guid, created_dt, updated_dt
- forum.blockstack.org/t/proposal-create-a-document-collection-for-cross-app-data-sharing/9286/2
- github.com/blockstack/blockstack-collections
- settings file
- all notes in a folder named notes, settings.json is in root or another folder
- should have version.json file?
- how to set filename? worst case: same account creat a file at the same time on web and mobile?
- read file one by one, performance issue? one round trip, get everything?
*** gaia api
- put file
- list file names with pagination
- read file
** How to extract web page content?
- Use Google cloud storage to serve html/js/css files
- If require, client (ReactJS) connects to server (Google App Engine) i.e. extract information from an url, security issue?
+ jsonp
+ use backend code
+ window.postMessage
+ Cross-Origin Resource Sharing (CORS)
+ ref: https://javascript.info/fetch-crossorigin, http://www.eriwen.com/javascript/how-to-cors/, https://www.moxio.com/blog/12/how-to-make-a-cross-domain-request-in-javascript-using-cors, https://jvaneyck.wordpress.com/2014/01/07/cross-domain-requests-in-javascript/, https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/
- Might need to be Python server, not NodeJS server as features needed are about information extraction i.e. beautifulsoup or libraries in NodeJS should be available
- Believe that with Google App Engine standard enviroment, external libraries like beautifulsoup can be installed.
** website analytics
*** tools
- usefathom.com/, $14 per month -> too expensive?
- Google analytics is free but privacy?
- github.com/PostHog/posthog - self host
- matomo.org
- plausible.io
- mixpanel.com
** monorepo
- webapp, firefox extension, chrome extension, android with react native, ios with react native
** CI/CD
*** Github actions
-
** test
This and CI/CD are very important!
*** tools
- github.com/enzymejs/enzyme
- browserstack.com
- lambdatest.com
- pact.io
- browsersync.io
- developers.google.com/web/tools/lighthouse
- cypress.io - a complete end-to-end testing experience
- jest
** tools
- jdenticon.com - generate a random image placeholder for a missing image
- greensock.com - animation, not totally free
- relay.dev - the production-ready GraphQL client for React
- immortalDB - redundant store data in indexedDB, localStorage, and cookies
- reqres.in - test your front-end against a real API
- puppeteer - provides a high-level API to control headless Chrome
** resources
- github.com/pujolchr/aStackToRead
- github.com/ShafiqShams/reacttodosapp
- github.com/bingex/react-crud
- github.com/khanshamim/react-application
- github.com/donovantc/react-shared
- github.com/ksholla20/react-native-react-monorepo-starter
** react native
*** blockstack-native
**** requirements
- sign up, sign in, sign out
- listFiles, getFile, putFile, deleteFile
*** tailwindcss for react-native
**** requirements
- width query: default, sm, md, lg,
- custom classnames
*** auto responsive grid layout
**** requirements
- 1 col, 2 cols, 3 cols
- animation on add, remove
- render on the fly like flatlist
*** share extension
**** requirements
- share url to and save in a background
*** change list names
*** popup with back press
*** animation
* requirement
** Add link
** List views, view more
** Click to visit, Copy link, share link, delete link
** search/filter with regex pattern
** Getting started screen guide
** Extensions on firefox, chrome
** Mobile apps - react native
** Beautify - extract web page title, images
** Trash - 30 days before delete
** tagging/labelling/archieved
* design user experience (UI/UX)
** theme
- minimalism
+ youtu.be/fzwOBOjSto8?t=224
+ redstapler.co/web-design-trends-2019/
+ youtube.com/watch?v=z0GChBEw4BU
+ kaycinho.com/website-trends-2019-web-design/
** inspiration
- miro.com/stickies-capture
- bizy.com
- pros.com
- upperquad.com
- github.com/cssninjaStudio/fresh
- webartisan.be
- github.com (dark theme)
- www.mozilla.org (white navbar)
- bvd.se
- brander.ua
- adoric.com
- www.schwarz-matt.com
- minimalissimo.com
- apple.com
- wsj.com
- medium.com
- brand.uber.com
- www.designsystems.com/sections/getting-started
** logo
*** color
- black/white/silver/grey: balance, neutral, calm i.e. Apple, Nike, Puma, Honda, Wiki, CartoonNetwork, Benz, wsj, gucci, channel, prada, nytimes.com, sony, uber, medium.com
*** fonts for brandname
- Moiser techno Font - www.fontspace.com/moiser-techno-font-f16409
- Chainsaw Geometric Font - www.fontspace.com/chainsaw-geometric-font-f9174
- gtek-minimal - www.qbotype.com/pagina-del-producto/gtek-minimal-1
- amirox - www.qbotype.com/pagina-del-producto/amirox-v16-1
- HFF Modern Strand Font - www.fontspace.com/hff-modern-strand-font-f9019
- misirlou - www.fontsc.com/font/misirlou
** icon
-
** illustration
- undraw.co/search -> collecting
- undraw.co/search -> bookmarks
** color pallete
- All black on logo and landing page, colorfy with moving shapes like upperquad.com
- On landing page requires black-white illustrator
- On main page, primary color is blue like pros.com and dark shade is like Blockstack color, others generate from colormind.io
- tailwind css
- lyft colors
- brand.uber.com/guide#color-specialty-colors
- Action color: dark grey (close to black)
** font
- type
+ Helvetica Now Display, Helvetica Now Text
+ Rubik
+ Work Sans
+ tinkov.info/gilroy.html ($180)
+ Eina03
+ MaisonNeue
+ Uber Move Text
+ choose from www.typewolf.com/google-fonts
- size: 16px
- line height: ?
- color: ?
- weight: ?
- ref: https://ant.design/docs/spec/font
** layout
*** attributes
- display-type/position-type
- margin/padding
- width/height
- color
- font-size
- font-color
- font-weight
- line-height
- letter-spacing
- border-size
- border-color
- corner-radius
** landing page
*** nav
- BRACE
*** 1st section
- Save links to visit later
- Blockstack login/signup button
- *illustrator*
*** 2nd section
- Easy ways to save
- 1. click add bottom
- 2. type brace.to/ at url bar
*** 3rd section
- All in one place
- *Show main page with beautiful contents*
*** 4th section
- Privacy, your own identity and full control of you data
*** 5th section
- Start saving now!
- Blockstack login/signup button
*** footer
- twitter, github
- about, terms of service, privacy
- faq
+ How different from pocket?
+ What are the benefits of using Brace?
+
** main page
*** Auto Responsive Grid Layout
- github.com/xudafeng/autoresponsive-react
- github.com/tsuyoshiwada/react-stack-grid
- github.com/dantrain/react-stonecutter
** main page w/o items
*** tutorial
-
* Implementation
** project
*** create-react-app
- medium.com/@xijo/create-react-app-with-tailwind-via-postcss-plus-purgecss-5c36b4c33ba7
*** dependencies
- tailwindcss
- postcss-cli
- autoprefixer
- purgecss
- react
- react-dom
- react-scripts
+ webpack
+ babel
+ postcss
+ autoprefixer
+ workbox
- redux
- react-redux
- axios
- redux-thunk
- (No use redux-form for more control over action and reducer)
- redux-offline
- (No use router for more customization)
- (No use context as use redux)
- ? hook ?
- blockstack-js
- blockstack-connect
- url-parse
** React
*** entry point
- index.js
*** components
- App.js
- Loading.js
- Landing.js
- TopBar.js
+ redux-form on search and add
- BottomBar.js
- CardList.js
- CardItem.js
- Settings.js
- Adding.js
- DialogBox.js (Modal.js)
- Popup.js
+ If use redux, there will be only one popup, but how to click outside to close?
- Link.js
*** router
- switch (medium.com/@daveford/react-router-alternative-switch-acd7961f08db)
- if switch is not ok, use router5 (life.wongnai.com/router5-39d97bd9e48d)
** Redux & Redux-Offline
*** state
- link
+ version
+ id (UUID)
+ url (+ domain_name)
+ No need -> list_name: default, archive
+ added_dt
+ did_beautify
+ title
+ favicon
+ screenshot
+ beautified_dt
+ No need -> did_remove
+ No need -> removed_dt
- links: {key is link id, value is an object of its values}, sort?
+ MyList
~ adding
~ added
~ removing
+ Trash
~ adding
~ added
~ removing
+ Archieve
~ adding
~ added
~ removing
*** actions
- SIGN_IN
- SIGN_OUT
*** reducers
- userReducer
** Workbox
** Blockstack (js, Gaia, connect)
*** sign in
*** sign out
*** fetch with pagination. sort?
- featch all file with listFiles
- save all files in root path both links and settings so that when calling listFiles, all files come at once
*** save. id?
** Auto Responsive Grid Layout
-
** Search
- lucaongaro.eu/blog/2019/01/30/minisearch-client-side-fulltext-search-engine.html
** API server
*** Google app engine
*** Puppeteer
** steps
- yarn create react-app bracedotto --template cra-template-pwa
- yarn add tailwindcss postcss autoprefixer
- yarn add @tailwindcss/forms @tailwindcss/typography @tailwindcss/aspect-ratio @tailwindcss/line-clamp
- no need for dev dependencies as this's not a node app
- yarn add redux redux-loop react-redux reselect
- yarn add https://github.com/stxapps/redux-offline#028205cec27dcf1ae05e310fc7e45779ee908949
- yarn add @stacks/auth @stacks/storage @stacks/wallet-sdk @stacks/connect @stacks/encryption
- Make sure history works:
+ Address bar i.e. change path, change hash!
+ redirect back i.e. from blockstack or other websites
+ back, forward button
+ button, tag <a> in the app
- yarn add url-parse
- Hack for back button
+ Need 2 history states for when press back, the previous state still be our app and can handle in onpopstate
+ Need to provide each history state a number for knowing back press or forward press or tag <a> click
+ ref: stackoverflow.com/questions/8980255/how-do-i-retrieve-if-the-popstate-event-comes-from-back-or-forward-actions-with/49329267#49329267, medium.com/@subwaymatch/disabling-back-button-in-react-with-react-router-v5-34bb316c99d7
- yarn add react-graceful-image
- yarn add axios
- yarn add file-saver
- yarn add @welldone-software/why-did-you-render
- yarn add framer-motion
- yarn add @types/node @types/react @types/react-dom @types/jest @types/url-parse @types/file-saver
- yarn add @wewatch/lexorank
- webpack 5 no longer include polyfills for node.js core modules by default
+ yarn add react-app-rewired
+ call react-app-rewired in package's scripts
+ create a config-overrides.js file in the root directory
+ install all polyfills: yarn add assert buffer crypto-browserify process stream-browserify util
- yarn add blueimp-load-image
- yarn add idb-keyval
- yarn add jest-diff
** attribution
- tailwindcss, postcss, purgecss
- uirefactoring
- figma
- iconmonstr.com
- undraw.co
- getpocket.com
- saved.io
- udemy
- react, create-react-app
- redux, redux-thunk, redux-offline, react-redux
- github.com/ConnorAtherton/loaders.css
- loading.io/css/
- react-stack-grid
- react-graceful-image
- jdenticon
- leaverou.github.io/css3patterns
- freefrontend.com/css-background-patterns
- images
+ silver-watch-newspaper-magazine-preview.jpg: https://www.pickpik.com/silver-watch-newspaper-magazine-flower-pink-69937
+ black-and-white-electronic-device-cup-of-espresso-on-saucer-beside-spiral-note.jpg: https://www.pikrepo.com/frbdj/black-and-white-electronic-device-cup-of-espresso-on-saucer-beside-spiral-note
+ silver-macbook-beside-white-smartphone.jpg: https://www.pikrepo.com/fivtc/silver-macbook-beside-white-smartphone
+ green-typewriter-beside-green-hardbound-book-and-book.jpg: https://www.pikrepo.com/fenlp/green-typewriter-beside-green-hardbound-book-and-book
+ cup-of-coffee-beside-gray-laptop-on-brown-wooden-desk.jpg: https://www.pikrepo.com/femfv/cup-of-coffee-beside-gray-laptop-on-brown-wooden-desk
+ macbook-air-beside-white-ceramic-mug-on-brown-wooden-table.jpg: https://www.pikrepo.com/fevvb/macbook-air-beside-white-ceramic-mug-on-brown-wooden-table
+ person-using-gray-laptop-computer.jpg: https://www.pikrepo.com/fefte/person-using-gray-laptop-computer
+ black-and-gray-laptop-computer-macbook-beside-drinking-glass-on-wooden-table.jpg: https://www.pikrepo.com/fnejx/black-and-gray-laptop-computer-macbook-beside-drinking-glass-on-wooden-table
+ black-ceramic-mug-near-three-smartphones-on-white-wooden-desk.jpg: https://www.pikrepo.com/fprob/black-ceramic-mug-near-three-smartphones-on-white-wooden-desk
+ gold-iphone-6-on-white-book-near-gray-laptop-computer.jpg: https://www.pikrepo.com/fefsm/gold-iphone-6-on-white-book-near-gray-laptop-computer
+ cup-of-coffee-beside-macbook-pro.jpg: https://www.pikrepo.com/fpgac/cup-of-coffee-beside-macbook-pro
+ silver-iphone-6.jpg: https://www.pikrepo.com/felsy/silver-iphone-6
+ silver-iphone-6-beside-white-ruled-paper.jpg: https://www.pikrepo.com/fntiz/silver-iphone-6-beside-white-ruled-paper
+ eyeglasses-with-black-plastic-frame-on-top-of-open-book.jpg: https://www.pikrepo.com/flqlq/eyeglasses-with-black-plastic-frame-on-top-of-open-book
+ macbook-pro-on-brown-table.jpg: https://www.pikrepo.com/fpgml/macbook-pro-on-brown-table
+ white-ceramic-teacup-with-saucer.jpg: https://www.pikrepo.com/ferbh/white-ceramic-teacup-with-saucer
+ white-pen-on-white-notebook-beside-the-orange-ceramic-coffee-cup-with-saucer-located-on-top-of-white-table.jpg: https://www.pikrepo.com/fqdhp/white-pen-on-white-notebook-beside-the-orange-ceramic-coffee-cup-with-saucer-located-on-top-of-white-table
+ white-ipad-on-brown-wooden-table.jpg: https://www.pikrepo.com/fffbs/white-ipad-on-brown-wooden-table
+ macbook-and-teal-ceramic-kettle-on-white-table.jpg: https://www.pikrepo.com/frwgk/macbook-and-teal-ceramic-kettle-on-white-table
+ gray-zenit-e-slr-camera-on-brown-surface.jpg: https://www.pikrepo.com/femzx/gray-zenit-e-slr-camera-on-brown-surface
+ eyeglasses-on-top-of-opened-book.jpg: https://www.pikrepo.com/flobr/eyeglasses-on-top-of-opened-book
+ turned-off-black-laptop-computer-on-green-grass-field.jpg: https://www.pikrepo.com/ferad/turned-off-black-laptop-computer-on-green-grass-field
+ pencil-with-gray-sharpener-on-notepad.jpg: https://www.pikrepo.com/feayq/pencil-with-gray-sharpener-on-notepad
+ clear-light-bulb.jpg: https://www.pikrepo.com/frelq/clear-light-bulb
+ brown-wooden-framed-chalkboard.jpg: https://www.pikrepo.com/fllvu/brown-wooden-framed-chalkboard
+ clear-light-bulb-on-black-chalkboard.jpg: https://www.pikrepo.com/flsjo/clear-light-bulb-on-black-chalkboard
+ clear-sodium-bulb-lot-with-white-background.jpg: https://www.pikrepo.com/fllvk/clear-sodium-bulb-lot-with-white-background
+ happiness-illustration.jpg: https://www.pikrepo.com/fqlyh/happiness-illustration
+ led-bulb-on-black-surface.jpg: https://www.pikrepo.com/fodsy/led-bulb-on-black-surface
+ clear-halogen-bulb.jpg: https://www.pikrepo.com/frucq/clear-halogen-bulb
+ macbook-pro-full-of-sticky-notes.jpg: https://www.pikrepo.com/fpgbt/macbook-pro-full-of-sticky-notes
+ white-notebook-with-gray-ballpoint-pen.jpg: https://www.pikrepo.com/fpyvi/white-notebook-with-gray-ballpoint-pen
+ blue-ballpoint-pen-on-white-ruled-notebook.jpg: https://www.pikrepo.com/fentc/blue-ballpoint-pen-on-white-ruled-notebook
+ white-printing-paper-on-table.jpg: https://www.pikrepo.com/frmeg/white-printing-paper-on-table
+ white-notepad-between-color-pens.jpg: https://www.pikrepo.com/frcst/white-notepad-between-color-pens
+ black-ballpoint-pen-on-graphing-notebook.jpg: https://www.pikrepo.com/fobcp/black-ballpoint-pen-on-graphing-notebook
+ silver-framed-eyeglasses-beside-white-click-pen-and-white-notebook.jpg: https://www.pikrepo.com/frrsu/silver-framed-eyeglasses-beside-white-click-pen-and-white-notebook
* mvp
** No extensions yet
- Put app name on url
- Go to webapp and add manually
** blockstack apis
- register
- sign in
- sign out
- retrieve all bookmarks
- create a bookmark
- delete a bookmark
** monorepo
** react
- state, route, view
* fully-fledged
** todo
- BottomBar: jumpy when add popup transition with keyboard
- On mobile, just use div, not GridLayout
+ can use Tailwindcss space-y
+ no animation!
- Plus sign at the top of the page, what's about mobile?
** features
- download all
- delete all
- delete account
- create a new list
- set default list
- bulk edit
- empty trash
- select pattern or extract content
- sort, rearrange?
** webapp, firefox/chrome extensions, android, ios
* servers
** tailwindcss's live-server
- http://localhost:8080
- http://192.168.43.220:8080
** create-react-app's webpack dev server
- https://localhost:3000
- https://192.168.43.220:3000
** test server
- https://d2r7uroqj51uls.cloudfront.net
** prod
- https://brace.to
* devices
- Android phone: Firefox, Chrome
- iphone (emulator): Firefox, Chrome, Safari
- iPad: Firefox, Chrome, Safari
- Macbook: Firefox, Chrome, Safari
- Ubuntu laptop: Firefox, Chrome
* react-native
** steps
- npx @react-native-community/cli@latest init Bracedotto --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 react-native-swiper
- 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 https://github.com/stxapps/tailwind-rn#96848a8d2c2370e4f5e57a773ace172c4073157d
- npm i 'https://gitpkg.now.sh/stxapps/blockstack-react-native/BlockstackSDK?3d5bcd6ea9a17f00c76be5913009f2c02f13b95f'
- npm i https://github.com/stxapps/redux-offline#028205cec27dcf1ae05e310fc7e45779ee908949
- npm i @react-native-async-storage/async-storage @react-native-community/netinfo
- 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 react-native-document-picker react-native-share @react-native-clipboard/clipboard
- npm i react-native-flag-secure
- npm i jest-diff
- 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
- npm i react-native-image-crop-picker
- npm i react-native-modal react-native-popup-menu
- npm i @d11/react-native-fast-image
- change minSdkVersion to 28 in ./android/build.gradle
- Allow CORS access on https://brace.to/manifest.json
- Set up Android deep linking: reactnative.dev/docs/linking and developer.android.com/training/app-links/deep-linking
- npx react-native-asset to link assets i.e. fonts
+ medium.com/@mehrankhandev/ultimate-guide-to-use-custom-fonts-in-react-native-77fcdf859cf4
- ios
+ Edit PodFile: ios target 15.5, pod 'Blockstack'
+ First time must run:
~ cd ios
~ bundle install
~ bundle exec pod install
+ In Xcode, Bracedotto General -> Target iOS 15.5
+ In AppDelegate.m, moduleName:@"Brace"
+ Select Bracedotto in left pane, new -> swift file and generate header binding
+ Add image assets, update storyboard
+ Targets -> Bracedotto -> Build Settings -> Build Options -> Always embed Swift standard libraries: $(inherited)
- ios share extension
+ Target Bracedotto -> Info -> URL Types -> URL Schemes: bracedotto
+ Add RCTLinkingManager in AppDelegate.m
+ File -> New -> Target -> Share Extension
~ Save to Brace, Swift
+ Target Save to Brace -> General -> target iOS: 12.0
+ In Info.plist under Save To Brace
~ NSExtension -> NSExtensionAttributes -> NSExtensionActivationRule -> NSExtensionActivationSupportsWebURLWithMaxCount -> Number 1
+ Update ShareViewController.swift
- Add App groups from targets: Bracedotto and Save to Brace -> Signing & Capabilities
+ group.bracedotto.share
- CryptoSwift and NVActivityIndicatorView dependency
+ Add the dependency in Podfile with target 'Save to Brace'
- Add fonts to Save to Brace
+ Xcode's sidebar -> Resources, select all fonts
+ Xcode's rightbar -> Target Membership, select Save to Brace
+ Save to Brace -> Info.plist, add Fonts provided by application
- Targets -> Bracedotto -> Build Settings -> Packaging -> Product Name: Brace
* Debug
** Flipper
*** iOS
- stackoverflow.com/a/74030603
- show hidden files: press the “Command” + “Shift” + “.” (period) keys
* test cases
- web, mobile
- PC, laptop, tablet, phone
- features
+ Landing, About, Terms, Privacy, Support
+ Sign up, Sign in
+ Main
+ List links, fetch more
+ New link
~ bottom bar, top bar, empty page, share extension
+ move link, delete link
~ bottom bar, top bar
+ Bulk edit: move notes, permanently delete notes
+ Search
~ add new link, move/delete link, bulk edit
~ pin, unpin, move pin
+ List list names, change list name
+ Card, List
+ New list name, edit list name, move list name, delete list name
+ Popups: CardMenu, ConfirmDelete, MoveTo, ListsMenu
+ Settings: account, subscription, data, lists, misc, about
+ Pin, unpin, move pin
+ Custom link's title & image
+ WHT_MODE, BLK_MODE
* brace-server-worker
** Cloud Run and no need all below
- yarn run deploy
- might need to increase memory
- Set schedule */30 * * * *
** Creat an instance
- us-central1-a
- Choose e2-medium (2 vCPU, 4GB memory)
- Ubuntu 20.04LTS on balanced persistent disk 10 GB
- Allow full access to all Cloud APIs
- **Uncheck** Delete boot disk when instance is deleted
** Access the instance
- gcloud compute ssh --zone=us-west1-b brace-worker-002
- If found WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
+ exit and run the command explained below the warning i.e. ssh-keygen -f "/home/linux/.ssh/google_compute_known_hosts" -R "compute.8353753600559446613"
** Setup the instance
- sudo apt update, sudo apt upgrade
- install nvm, nodejs, yarn
- git clone https://github.com/stxapps/brace-server-worker.git
- cd brace-server-worker
- git pull
- yarn
- if puppeteer errors, try stackoverflow.com/questions/66214552/tmp-chromium-error-while-loading-shared-libraries-libnss3-so-cannot-open-sha
+ ldd node_modules/puppeteer/.local-chromium/linux-XXX/chrome-linux/chrome | grep not
- curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh && sudo bash add-google-cloud-ops-agent-repo.sh --also-install
+ cloud.google.com/stackdriver/docs/solutions/agents/ops-agent/installation
** Add a startup script
- As startup script is executed by root user, need to specify running commands by linux user
- use 'sudo -i' to switch to root user and test the script below
- startup script in Custom metadata, key: startup-script, value:
#! /bin/bash
sudo -u linux bash -c 'cd /home/linux/brace-server-worker; mkdir -p ./logs; NOW=$(date +'%Y%m%d%H%M%S'); /home/linux/.nvm/versions/node/v16.18.1/bin/node --experimental-specifier-resolution=node src/index.js > "./logs/log_${NOW}.txt" 2>&1; sudo shutdown -h now'
- *Check node version as it's hard coded!*
** Schedule the instance
- IAM
+ Check include Google-provided role grants
+ Edit on service-57708091218@compute-system.iam.gserviceaccount.com
+ Add role Compute Instance Admin (v1)
- Under VM instances, select tab Instance Schedule
+ Name: brace-server-worker-scheduler
+ Region: us-central1
+ Start CRON expression: 0 * * * *
+ Stop CRON expression: 20 * * * * (at least 15 mins apart)
+ Time zone: Indochina Time (ICT)
+ Add the instance to the schedule
- ref: cloud.google.com/compute/docs/instances/schedule-instance-start-stop
** Fix disk full
- df -k
- likely it's snaps: du -h /var/lib/snapd/snaps
- remove old snap: sudo bash remove-old-snaps.sh
- ref: itsfoss.com/free-up-space-ubuntu-linux/
* Clean up GCloud DataStore
- Use GCloud console
- Delete error extracted results
+ select * from ExtractedResult where status = 'EXTRACT_ERROR'
- Delete old extracted results
+ select * from ExtractedResult ORDER BY extractedDT
* In-App Purchase
** Setup in Connect
- Need to provide a screenshot and description for review
- Get App-Specific Shared Secret in Features: In-App Purchases tab
- Sandbox Testers
+ Use an email address that has never been used as an Apple ID or used to purchase iTunes or App Store content. Consider creating a dedicated email address for each sandbox tester.
- Add server url to URL for App Store Server Notifications in General -> App information -> v2
- Add a link Terms of Service in the App Description
** Setup in XCode
- Add In-App Purchase capability in Xcode
- When testing in-app purchases in the sandbox environment, make sure you’re running a development-signed build of your app; production-signed builds use the production environment.
** Setup in React Native
- yarn add react-native-iap (StoreKit original API)
- Add missingDimensionStrategy 'store', 'play' in defaultConfig in android/app/build.gradle
** Setup in Play console
- Release to Closed testing: Alpha
- Add Testers and the license testers
+ Join in https://play.google.com/apps/testing/com.bracedotto
- Add iap subscription and activate
- Use same versionCode and versionName as in Closed testing
- Setup -> API access (account level, both apps can use it)
+ Create a new Google Cloud Project
+ Create new service account, choose Editor for the project access. Allow all permissions for financial data, create new key
** Setup in Google Cloud
- Add pub/sub topic: projects/iap-001/topics/playstore-notifications-bracedotto
+ Justnote can also use this pub/sub topic and the subscriber!
+ Should name just playstore-notifications as can reuse with others!
- Change to push with the server endpoint, Set the subscriber to never expire
- Add permission to the topic
- Add the topic in Play Console -> Brace.to app -> Monetization setup
** Setup in iap-server
- cd Drive/Workspace/iap-server
- gcloud app create --project=iap-001 --region=us-central
- assume unchanged: git update-index --assume-unchanged src/appstore-keys.json src/playstore-service-account.json src/paddle-keys.json
- yarn add googleapis node-apple-receipt-verify
- Create Application Default Credential (ADC)
+ select project: iap-001, go to IAM & Admin -> Service Accounts -> Select App Engine default service account -> Keys -> Add Key -> Create new Key
+ Move the file to ~/.config/gcloud/legacy_credentials/brace@brace.to
+ Refer to it in package.json -> scripts -> start-local
+ cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/datastore
+ cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
** Test
*** iOS
**** XCode (developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode)
- Create supporter.storekit
- In Edit Scheme... -> Run -> Options, Storekit Configuration: supporter.storekit
- Choose Build Configuration: Debug, Debug executable, and localhost in Info.plist
- Choose supporter.storekit before
+ Test interrupted Purchases by Editor -> Enable Interrupted Purchases
+ Test failed transactions by Editor -> Fail transactions -> SKErrorUnknown
+ Manage Transactions by Debug > StoreKit > Manage Transactions
- Don't forget to change Storekit Configuration back to None
**** Sandbox (help.apple.com/app-store-connect/#/dev7e89e149d)
- Don't need to sign out, just run the app in *debug mode*, when make a purchase, there will a popup to use test user
- Sign in with test id: testuser01@brace.to, normal pass + Conf in the popup
- Manage the test user in Settings -> App Store -> Sandbox account
*** Android
- Join a test program
- Choose approve purchase, or reject purchase in both purchase popup and in subscription management in Google Play App
- Choose cancel subscription in subscription management in Google Play App
* 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-flag-secure
- npm i react-redux redux redux-thunk reselect
- npx expo install redux-devtools-expo-dev-plugin
- npm i url-parse @wewatch/lexorank
- npm i jest-diff@29.7.0
- npx expo install expo-share-intent
- npx expo install react-native-file-access
- npx expo install expo-localization
- npx expo install expo-iap
- npx expo install expo-document-picker
- 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 @react-native-async-storage/async-storage
- npx expo install @react-native-community/netinfo
- npm i https://github.com/stxapps/redux-offline#028205cec27dcf1ae05e310fc7e45779ee908949
- npm i react-native-swiper
- npx expo install expo-clipboard
- npx expo install expo-image-picker expo-image-manipulator
- npx expo install expo-image
- 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/Brace.xcworkspace
+ choose Brace on the right pane
+ targets: Brace, on General:
~ update Version, App Category: Productivity, Display Name: Brace
+ targets: Brace, on Signing & Capabilities, add In-App Purchase
+ targets: Brace, on Build Phases, add Target Dependency: SavetoBrace
+ targets: SavetoBrace, on General:
~ update Version, Miminum iOS, Display Name: Save to Brace
+ targets: SavetoBrace, on Signing & Capabilities, select team
- android
+ copy brace-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 bracedotto
+ Choose typescript, tailwind and eslint
+ scripts dev - add --experimental-https --hostname
- npm i redux react-redux redux-thunk reselect
- npm i https://github.com/stxapps/redux-offline#028205cec27dcf1ae05e310fc7e45779ee908949
- 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 react-graceful-image file-saver @wewatch/lexorank blueimp-load-image idb-keyval
- npm i jest-diff@29.7.0
- npm i motion
- npm i p-queue
- 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
** Steps on AWS
1.1 In AWS S3 -> Permissions -> CORS
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [],
"MaxAgeSeconds": 31536000
}
]
1.2 Create custom cache policy: CustomUseOriginCacheControlHeaders-QueryStrings
1.3 Create custom origin request policy: CustomCORS-S3Origin
1.4 Create CF functions: test-brace-web-rewrite, brace-web-rewrite
2.1 upload files to S3, don't invalidate CF yet!
2.2 In AWS S3 -> Properties -> Static Website Hosting -> Error document change to 404.html
2.3 Set CF behavior -> Cache key and origin requests to recommended
Cache: CustomUseOriginCacheControlHeaders-QueryStrings
Origin request: Managed-CORS-S3Origin
2.4 Set CF behavior -> Function associations -> Viewer request -> brace-web-rewrite
2.5 invalidate CF