Coquill
Coquill is a real-time collaborative text editor for writing screenplays. Based on your selection, the editor will automatically format your text and provide text styling if need be. Once you have created a screenplay, the editor will project colors on the page which map to the context of your text. https://github.com/queenplay-associates/coquill
Created by
β€οΈ Eleniπ Samanthaπ Christinaπ GuangοΈ οΈ
Tech Stacks
React, Redux, Firebase, Immutable.js, Webpack, Babel, React-hot-loader, Sentiment (in progress)
Data Flow
- Data from Coquill to Firebase ππ½
πͺ :- Typed words - - -> Redux (locally stored as a tree structure) - - > dispatched to Firebase (stored as a flat-ish list consisting of Redux actions, which carry the word character bits data)
- Data from the Firebase to Coquill
π§ β:- Database listens to each unique action key on change - - -> those listeners trigger Redux actions - - -> local state gets updated - - -> React component renders individually - Within the formatting toolbar, each formatting type generates an individual React component, this component also contains a reference key to its type (Action, Dialog, Scenes, etc) Ex: A screenplay might have 50+ rendered blocks, the State has potential fixed amount of child nodes. (Action, Dialog, Scene Headings, etc) The tree-like structure. The tree structure grows like that.
- Each dispatched action with word content also carries writer's info which is passed on from firebase Auth, when writing in Coquill, writer notice the other writer's current editing place by pressing the 'tab' key.
Reducer sample
export const setValue = (value, index, name) => ({
type: SET_VALUE,
value,
componentKey: index,
name
})
...
const reducer = (state = OrderedMap(), action) => {
...
case INSERT_AFTER:
itemsBefore = state.takeUntil(({key}) => key === action.afterKey)
const after = state.get(action.afterKey)
itemsAfter = state.skipUntil(({key}) => key === action.afterKey)
.delete(action.afterKey)
return itemsBefore
.set(action.afterKey, after)
.set(action.actionKey, {
type: action.objectType,
key: action.actionKey,
})
.merge(itemsAfter)
...
case SET_VALUE:
case CHANGE_TYPE:
return state.update(action.componentKey, item => itemReducer(item, action))
default: return state
}
}
...
function itemReducer(item = {}, action) {
const {type} = action
if (type === SET_VALUE)
return {...item, value: action.value, name: action.name}
if (type === CHANGE_TYPE)
return {...item, type: action.objectType}
return item
}
Firebase sample
-Screenplays
-L-Pdurudnr1DSlx08BO
-actionKey: "-L-Pdurudnr1DSlx08BO"
-componentKey: "-L-O8hlCEDLV_z3CPTYm" // each unqic action may share same componentKey
-name: "SJ"
-type: "SET_VALUE"
-value: ""One of our biggest challenges was..."
-Users
-xOedKRr8zoVvKzhgby1xx0 //user's auth id
-contributedScreenPlays: "Demo Day"
-displayName: "Spike Jonze"
-permissions
-photoURL:
Get started:
git clone git@github.com:queenplay-associates/coquill.git
npm install
npx firebase init
npm start