GithubHelp home page GithubHelp logo

cybersemics / em Goto Github PK

View Code? Open in Web Editor NEW
261.0 12.0 88.0 249.04 MB

A beautiful, minimalistic note-taking app for personal sensemaking.

License: Other

HTML 0.07% CSS 2.33% JavaScript 2.17% TypeScript 95.14% Shell 0.07% Java 0.05% C 0.01% Swift 0.12% Objective-C 0.01% Ruby 0.03%
outliner sensemaking knowledge-management tools-for-thought note-taking

em's Introduction

em

em is a beautiful, minimalistic note-taking app for personal sensemaking.

  • cognitively-informed - Supports focus, nonlinearity, and associative connectivity.
  • process-oriented - Facilitates flow and organic thinking.
  • semiotic - Mediates concept through a monistic, contextual semiotic web.

Documentation

  • Overview - An overview of the architecture, data structures, and tips for contributors.
  • Internal API - Autogenerated TypeDoc documentation for all internal modules.
  • Roadmap - A high level overview of the project, including vision and objectives.

Setup

yarn install

To setup the websocket server for device syncing, you also need to install dependencies in the server subpackage:

cd server && npm install

Web App Development

Start the live-reload server for local development:

# starts a live-reload server at http://localhost:3000
npm start

To enable device syncing, start the websocket server:

# starts a hocuspocus server at http://localhost:3001
npm run websocket-server

For more information about configuring and deploying the websocket server, see https://github.com/cybersemics/em/tree/yjs-multiplex/server.

Native App Development

To get started, run npm run cap:ios or npm run cap:android.

Scripts:

  • cap:ios - Generates iOS project files with capacitor and opens the project in XCode. Requires XCode and CocoaPods to be installed. Choose your device target and hit Play in XCode to build and run the app.
  • cap:android - Generates Android project files with capacitor and opens the project in Android Studio.
  • cap:copy - Copies the web app build and capacitor configuration file into the native platform project. Run this each time you make changes that are not picked up by the live-reload server, and when you change a configuration value in capacitor.config.ts.
  • cap:sync - Runs cap:copy and updates native capacitor plugins.

The above scripts run in development mode by default. You can copy or sync in production mode with these:

  • cap:copy:prod
  • cap:sync:prod

Deployment

em is an offline-first app that can run on a static web server.

Environment variables are set in the appropriate .env file: .env.development and .env.production. Only .env.production is kept in source control. Environment variables that are prepended with VITE_ will be bundled with the build and available client-side.

# build the static HTML/CSS/JS app in the /build directory
npm run build

# Run the static build with npx serve -s build -l 3000
npm servebuild

Device syncing requires a websocket server. You can start the websocket server with:

npm run websocket-server

See: https://github.com/cybersemics/em/tree/yjs-multiplex/server

Component Hierarchy

Root containers:

Each thought consists of many layers of components that provide various functionalities. This is necessary from a performance perspective to avoid re-rendering all thought components when a small slice changes, when a thought falls outside the viewport and can be virtualized.

└─Content
  └─LayoutTree
    └─LayoutShim
      └─VirtualThought
        └─ThoughtContainer
          ├─Bullet
          └─StaticThought
            ├─ThoughtAnnotation
            │ └─StaticSuperscript
            └─Editable
            │ └─Superscript
  • <Content> - Root container that defines the margins of the thoughtspace and handles clicking on empty space.
  • <LayoutTree> - Renders all visible thoughts as absolutely positioned siblings to allow for conditional rendering of ancestors, list virtualization, and cross-hierarchy animation.
  • <VirtualThought> - Conditionally renders a shim when the thought is hidden by autofocus. The shim is a simple div with a height attribute matching the thought's height.
  • <ThoughtContainer> - Contains the Bullet, ThoughtAnnotation, and StaticThought for a single thought.
  • <Bullet> - This is, unsurprisingly, the bullet of the thought.
  • <StaticThought> - Contains the Editable and ThoughtAnnotation.
  • <ThoughtAnnotation> - A non-interactive, hidden clone of the Thought that is used to position the Superscript.
  • <Editable> - Renders the thought text as a content-editable and handles live editing, throttled updates, selection, pasting, and all other editing capacities.

Known issues

  • Not tested in Firefox

em's People

Contributors

ankitkarna99 avatar anmolarora1 avatar aqkhan avatar artmyweb avatar brunokiafuka avatar dependabot[bot] avatar dezzzus avatar duongtungls avatar edsonayllon avatar enuke-shahroz avatar esandez93 avatar hsmr29 avatar incora-dev avatar joy0316webiee avatar karunkop avatar linghong avatar mekanix avatar molecula451 avatar muganwas avatar mul53 avatar nepali-prabhat avatar ogutu-brian avatar onurpolattimur avatar raineorshine avatar ruchijn avatar samvelarm avatar shresthabijay avatar sparklingw avatar thsudo avatar umair-khanzada avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

em's Issues

[iOS] Caret drifts during navigation

When navigating, the content is smoothly translated to keep the focused content in view, but the caret drifts. Tested on iOS 13.1.3.

Expected Behavior

The browser cursor should stay in place (not move relative to its contenteditable).

Actual Behavior

On iOS, the caret drifts out of place during the animation.

Video:
https://youtu.be/Poo61duk41w

Encode "~" character in url

Adding the "~" character to the end of a thought breaks the url refresh because it interferes with the Context View url encoding.

Steps to reproduce

  • Add the "~" character to the end of a thought
  • With the cursor on this thought, refresh the page

Current Behavior

  • Cursor disappears
  • Causes a "restoreSelection" error

Expected Behavior

  • When the cursor is on a thought containing "~" and the page is refreshed, the cursor should be restored properly and no error should occur.
  • The "~" should be encoded in the url if it is part of the value of a thought, and decoded when parsed out.
  • Context View url encoding with unencoded "~" should be preserved. ~ is used to encode the Context View state in the URL so that the page can be refreshed and re-open in the Context View.

Enter Ctrl + Shift + S, or click the Screen Shot 2020-03-27 at 7 09 58 AM button in the toolbar to activate the Context View on a given thought. To give a thought multiple contexts, just add it to two different places in the thoughtspace.

Fix drag and drop in context view

  • Drag thought into context view
  • Drag thought into child of context
  • Drag context out of context view
  • Drag child of context out of context view

Create Personas

What do they like about em?
Why do they use em over other things?

Allow tap on bullet

  • Move bullet character from CSS to markup
  • onClick: setCursor OR cursorUp
  • do not enter editing mode

Superscript positioning breaks on multi line items

The superscript is out of position on multi-line thoughts.

Note that superscripts are rendered within <ThoughtAnnotation> in which text is duplicated but hidden in order to position the superscripts in the correct place without interfering with editing.

[Old] Settings page

Create a Settings page (full-screen modal, like the shortcuts modal) and move the settings currently in the footer to the Settings page.

  • dark mode
  • swap swipe right/left
  • auto sort
  • refresh

Replace em icon with home icon

Replace the em icon (which deceptively looks like a hamburger menu) with a material UI home icon:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/><path d="M0 0h24v24H0z" fill="none"/>
</svg>

Restructure Codebase

Here is a potential list of goals I have identified for the rearchitecture. Please add your own and any comments here. We can use this issue to discuss and stay accountable to these goals.

  • Small files
  • Modular units
    ◦ clearly defined io
    ◦ not using shared, global state
  • Coherent architecture
  • Abstracted storage
    ◦ State
    ◦ Local
    ◦ Remote
  • Action creators
  • Coherent async actions
    ◦ thunk
  • Unit tests
  • Documentation
    ◦ Describing the architecture
    ◦ Describing how to do common tasks

Rerank subthoughts when sibling collision

When moving (dragging-and-dropping) a thought into a context, that context may have a thought with the same value, which may have different subthoughts (children). When this occurs, the subthoughts from the duplicate thoughts are merged.

Current Behavior

Subthoughts are combined into the destination (dropped) thought without modifying their rank, potentially creating duplicate ranks and/or resulting in an unexpected order.

Expected Behavior

The source subthoughts (drag) should be re-ranked starting with the rank of the last destination subthought (drop) + 1.

e.g. Given the following:

- A
  - B
    - x (rank 7)
    - y (rank 8)
- M
  - B
    - z (rank 4.5)

Moving /M/B into /A should result in the following:

- A
  - B
    - x (rank 7)
    - y (rank 8)
    - z (rank 9)
- M

Url doesn’t update when clicking the home “em” button

nor does it update when hitting "escape" while the cursor is on an item at the root level.

@rabbit This might be a good starter task! The history push/replace functionality will be easy to find, but you will still have to interface with some core concepts, such as below:

  • items: the array of descendants from the root to a given item, e.g. ['My Journal', '6/12/19', 'Happy']
  • itemsRanked: Similar to items, but stores each item as a { key, rank } pair to differentiate duplicate items in the same context.
  • cursor: where the cursor currently is; same data structure as itemsRanked but may include cycles to account for navigating across context views.

Ad hoc intersection of thoughts

  • e.g. I am in /Forrest/EGP and I want to intersect Questions
  • Option to collate results across subcontexts into single list

Production Viability: Database

Assess the scalability and production capacity of Firebase and compare it to other offerings.

Include:

  • justification of performance/space requirements
  • engineering effort
  • pricing estimates

Data merge

  • Simultaneous updates of contextChildren arrays must be merged
  • Store as object to avoid overwriting

Trace the line

  • Light up each segment as you swipe
    • Pass array of colors to GestureDiagram
  • Overlay with no touch interaction

Thoughts, Contexts, and Bindings -- A Data Model 💃

Thoughts, Contexts, and Bindings

This is a summary of our meeting discussion around the main data model which is similar to a graph.

Thought is a textual item
Context is an unordered set of Thoughts
Binding is an unordered set of Contexts

All links are bidirectionally between a Binding and a Thought. (e.g., Thoughts and Contexts do not link to other Thoughts or Contexts. a Context belongs to a Binding which links to Thoughts, a Thought links to a Binding which links to children)

In most cases a Binding will only contain a single Context but cases where multiple Contexts should be treated the same, they are housed under the same Binding

the UX process of creating a Binding of multiple contexts is TBD but should generally follow this flow:

  1. add a new thought (e.g., "Beta")
  2. navigate to the context view for that thought
  3. select a context to bind
  4. "Beta" now shows the children from the selected context binding

decoupling the binding would generally follow the reverse flow:

  1. select a thought to unbind
  2. thought shows context view for that thought (which includes the context it was previously bound to)
  3. switch out of context view

Rearchitecture

Here is a potential list of goals I have identified for the rearchitecture. Please add your own and any comments here. We can use this issue to discuss and stay accountable to these goals.

  • Small files
  • Modular units
    ◦ clearly defined io
    ◦ not using shared, global state
  • Coherent architecture
  • Abstracted storage
    ◦ State
    ◦ Local
    ◦ Remote
  • Action creators
  • Coherent async actions
    ◦ thunk
  • Unit tests
  • Documentation
    ◦ Describing the architecture
    ◦ Describing how to do common tasks

Context Layers (inner context)

A thought can contain more than one context to view

example Things I Like Todo could hold two context views

  • Things I Like Todo
  • Todo

to differentiate between context views, the active context view is underlined. if "Todo" is underlined then "Things I Like Todo" is inactive. when entering context view mode, the most general assumption possible is the default. if "Things I Like Todo" is a valid context view, it is selected by default otherwise "Todo" is selected by default.

to toggle between context views, first enter context view mode then (if the desired context is not already selected by default) tap the thought until the correct context view is underlined. each tap cycles through the possibilities in a loop. for the example, tapping would flip between "Things I Like Todo" and "Todo". tapping is only available once in a context view mode. outside of context view mode, tapping enters edit mode as expected.

open questions

  • should it matters where a user taps? I'm inclined to say it shouldn't so that tapping "Things" repeatedly toggles between "Things I Like Todo" and "Todo" which resolves ambiguous taps but then makes it maybe less intuitive that tapping the context the user wants to select won't necessarily select it?

New Tutorial

  • Start
    • You are now in your own, personal thought space. Everything you write will be stored privately on this device, no login required 🔑
    • Later, to access your thoughts from more than one device, log in with your Google account using the Login link at the bottom of the page.
    • Now, let’s begin exploring how to use em!
  • New Thought
    • First, let me show you how to create a new thought in em. This is done with a special gesture: →↓
    • Trace the line below with your finger to create a new thought.
  • Bullet types
  • Type Thought
  • New Thought - Repeat
    • Good work! Try creating a few more thoughts to get the hang of it.
  • Move Cursor
  • New Subhought
  • New Subthought - Repeat
    • You can even try nesting a thought inside a nested thought! Sorry, I get excited about meta-thoughts 😍
  • End Part I
    • How are you feeling? Would you like to learn more or play around on your own?
    • Learn more
    • Play on my own
      • Okay! To resume the tutorial, click the Tutorial link at the bottom of the page.
      • Fade in footer

Hash data key

  • Lowercase
  • Remove whitespace
  • Remove punctuation
  • Remove emojis only if there are other letters
  • Plurals
  • Migration
  • Fix contextChildren key after migration.

ngram Linking

An n-gram is a contiguous sequence of words within a thought.

  • Challenges
    • Must be taken into account by: add, delete, edit, contextView
    • Superscript spacing
      • Dynamically insert spacer sup
      • Re-insert spacer sup whenever it is deleted
      • Do not re-render editable while editing
    • Possible performance issues
    • Leave annotation infrastructure in place
  • Convert showContexts from bool to path
  • Incorrectly uses selection focus when trying to navigate into thought fragment context view descendants
    • Instead get from contextView
    • Only use selection focus at toggle context view
  • Add subkey property to cursor?
    • Might get lost constantly due to { key, rank } reconstructions
    • Can be derived from contextViews
      • No, because selection is lost once you start navigating in
  • Can't replace thought with ngram in contextViews as the path becomes ambiguous
    • The same ngam can exist in two siblings
  • Append ngram to items for contextView
    • Which makes sense as the ngram is a subsequent navigation step (a selection)

Create context above

Add an action creator and define a shortcut/gesture to create a new context above the current item, it between its current context and itself.

React Native

Determine the viability and effort involved in using the current codebase to create a native mobile app.

  1. What is required to migrate to React Native?
  2. How will browser features currently utilized be implemented on mobile? Include: low-level selection manipulation, zoom/scroll, authentication
  3. What unknowns can be isolated and tested, and what effort is involved?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.