Whatevernote is a pixel-perfect clone of Evernote.com, with React Quill. Create sortable notes and notebooks. Customize your creations with the React Quill text editor toolbar.
Explore the docs »
View Site
·
Report Bug
·
Request Feature
Notes are saved in the database as HTML strings. Images are converted to base64 encoded blob strings and save on the database as well.
Using focus and blur, notes are autosaved to the Redux Store and posted to the database upon logout.
.
├── dev-requirements.txt
├── requirements.txt
├── Dockerfile # Instructions to create image layer
├── Pipfile
├── Pifile.lock
├── README.md
├── app # Python & Flask backend folder
├── react-app # React with Redux frontend folder
├── images
Use these commands install and run the development version of Whavernote:
Notebook API Routes
#------------------------------------------------------------------------------
# Notebook Operation Functions
#------------------------------------------------------------------------------
def get_one_notebook(notebook_id):
notebook = Notebook.query.filter_by(id = notebook_id).first()
return notebook
def get_all_notebooks(user_id):
notebooks = Notebook.query.filter_by(user_id = user_id).all()
return jsonify({"notebooks": [notebook.to_dict() for notebook in notebooks]})
def add_notebook(user_id):
notebook_data = json.loads(request.data.decode("utf-8"))
notebook = Notebook(name = notebook_data,
user_id = current_user.id)
db.session.add(notebook)
db.session.commit()
return jsonify(notebook.to_dict())
def delete_notebook(notebook_id):
notebook = Notebook.query.filter_by(id = notebook_id).first()
db.session.delete(notebook)
db.session.commit()
return jsonify({"message": "Notebook successfully deleted"})
def edit_notebook(notebook_id):
edit_notebook_data = json.loads(request.data.decode("utf-8"))
notebook = get_one_notebook(notebook_id)
print(edit_notebook_data)
if notebook.name is not edit_notebook_data["name"]:
notebook.name = edit_notebook_data["name"]
if notebook.user_id is not edit_notebook_data["user_id"]:
notebook.user_id = edit_notebook_data["user_id"]
notebook.default_notebook = edit_notebook_data["default_notebook"]
db.session.commit()
return jsonify(notebook.to_dict())
#------------------------------------------------------------------------------
# RESTful Routes -- Notebooks
#------------------------------------------------------------------------------
#get_all
#add_notebook
@notebook_routes.route("/notebooks", methods=['GET', 'POST'])
def get_or_add_notebooks(user_id):
if request.method == 'GET':
return get_all_notebooks(user_id)
elif request.method == 'POST':
return add_notebook(user_id)
#delete
@notebook_routes.route("/notebooks/<int:notebook_id>", methods = ['DELETE'])
def delete_user_note(user_id, notebook_id):
return delete_notebook(notebook_id)
#edit
@notebook_routes.route("/notebooks/<int:notebook_id>", methods=['PUT'])
def edit_user_notebook(user_id, notebook_id):
return edit_notebook(notebook_id)
Tag Model
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
name = db.Column(db.String(30), nullable=True)
notes = db.relationship("Note", back_populates='tags',
secondary="notes_to_tags")
def to_dict(self):
return {
"id": self.id,
"user_id": self.user_id,
"name": self.name,
}
def other_to_dict(self):
return {
"id": self.id,
"user_id": self.user_id,
"name": self.name,
"notes": [note.to_dict() for note in self.notes]
}
Note Redux Store
import * as deepcopy from "deepcopy";
const GET_NOTES = "notes/GET_NOTES";
const REMOVE_NOTE = "notes/REMOVE_NOTE";
const EDIT_NOTE = "notes/EDIT_NOTE";
const ADD_NOTE = "notes/ADD_NOTE";
const SAVE_NOTE = "notes/SAVE_NOTE";
const get = (notes) => ({
type: GET_NOTES,
notes,
});
const edit = (note) => ({
type: EDIT_NOTE,
note,
});
const add = (note) => ({
type: ADD_NOTE,
note,
});
export const saveNote = (note) => ({
type: SAVE_NOTE,
note,
});
const remove = (userId, noteId) => ({
type: REMOVE_NOTE,
noteId,
userId,
});
export const getNotes = (userId) => async (dispatch) => {
const response = await fetch(`/api/user/${userId}/notes`);
if (response.ok) {
const notes = await response.json();
dispatch(get(notes));
}
};
export const createNote = (data, userId) => async (dispatch) => {
const response = await fetch(`/api/user/${userId}/notes`, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (response.ok) {
const note = await response.json();
dispatch(add(note));
return note;
}
};
export const editNote = (data) => async (dispatch) => {
const response = await fetch(`/api/user/${data.user_id}/notes/${data.id}`, {
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (response.ok) {
const notes = await response.json();
dispatch(edit(notes));
return notes;
}
};
export const deleteNote = (userId, noteId) => async (dispatch) => {
const response = await fetch(`/api/user/${userId}/notes/${noteId}`, {
method: "delete",
});
if (response.ok) {
const note = await response.json();
dispatch(remove(note.id, note.userId));
}
};
const initialState = {};
let newState;
const notesReducer = (state = {}, action) => {
switch (action.type) {
case GET_NOTES: {
newState = deepcopy(state);
newState = action.notes;
return newState;
}
case REMOVE_NOTE: {
const newState = { ...state };
delete newState[action.noteId];
return newState;
}
case SAVE_NOTE: {
const newState = deepcopy(state);
newState.savedNote = action.note;
return newState;
}
case EDIT_NOTE: {
return action.note
}
default:
return state;
}
};
export default notesReducer;
Want to contribute to Whatevernote? We're working on an open source release of our autosave functionality for use in all React Quill products. Create an issue to get started.