From fa263faaa946fe77253b85ddc90993884cef460f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 09:51:00 +0500 Subject: [PATCH 001/394] feat: add zustand --- apps/web/package.json | 3 ++- apps/web/yarn.lock | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index a7f8660a7..9f01bc12f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -20,7 +20,8 @@ "react-simple-dropdown": "^3.2.3", "react-virtuoso": "^0.12.3", "rebass": "^4.0.7", - "timeago-react": "^3.0.0" + "timeago-react": "^3.0.0", + "zustand": "^2.2.3" }, "devDependencies": { "babel-loader": "8.0.6" diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 83d27f8e7..003c69271 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -10982,3 +10982,8 @@ yargs@^13.3.0: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^13.1.1" + +zustand@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-2.2.3.tgz#07ee668bf600a5e0dcff8f8b60f35faa149f65d5" + integrity sha512-SSd5DzbwUN0b8ePW4I+8mSdXQc6UOqTgYzlMtoNvf7pogmFoXjeE0wZwCVopoZBnzz/uRBD2dsozzM2FXDQcXw== From 631219ef2f54c4f2750114fa2c8c3bb60d572da4 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 09:59:24 +0500 Subject: [PATCH 002/394] feat: create store --- apps/web/src/common/store.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/web/src/common/store.js diff --git a/apps/web/src/common/store.js b/apps/web/src/common/store.js new file mode 100644 index 000000000..0639990e7 --- /dev/null +++ b/apps/web/src/common/store.js @@ -0,0 +1,5 @@ +import create from "zustand"; + +const [useStore] = create(set => ({})); + +export default useStore; From f39832d775c4c7aa83b07e1304e7c02507fd8010 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 10:21:12 +0500 Subject: [PATCH 003/394] feat: add notebook state to store --- apps/web/src/common/store.js | 10 +++++++++- apps/web/src/views/Notebooks.js | 16 +++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/web/src/common/store.js b/apps/web/src/common/store.js index 0639990e7..70d1e0714 100644 --- a/apps/web/src/common/store.js +++ b/apps/web/src/common/store.js @@ -1,5 +1,13 @@ +import { db } from "./index"; import create from "zustand"; -const [useStore] = create(set => ({})); +const [useStore] = create(set => ({ + notebooks: db.notebooks.all, + addNotebook: async notebook => { + if (await db.notebooks.add(notebook)) { + set({ notebooks: db.notebooks.all }); + } + } +})); export default useStore; diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index bebb7f006..d2815cc1e 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -5,21 +5,11 @@ import { showSnack } from "../components/snackbar"; import Notebook from "../components/notebook"; import { CreateNotebookDialog } from "../components/dialogs"; import ListContainer from "../components/list-container"; +import useStore from "../common/store"; const Notebooks = props => { const [open, setOpen] = useState(false); - const [notebooks, setNotebooks] = useState([]); - useEffect(() => { - function onRefresh() { - setNotebooks(db.notebooks.all); - } - onRefresh(); - ev.addListener("refreshNotebooks", onRefresh); - return () => { - ev.removeListener("refreshNotebooks", onRefresh); - Notebooks.onRefresh = undefined; - }; - }, []); + const notebooks = useStore(state => state.notebooks); return ( <> @@ -62,7 +52,7 @@ const Notebooks = props => { topics }) ) { - setNotebooks(db.notebooks.all); + //setNotebooks(db.notebooks.all); setOpen(false); } else { showSnack("Please fill out the notebook title."); From 090937b57f33da4dc4727046e41a1255b4ecf40e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 10:21:29 +0500 Subject: [PATCH 004/394] feat: remove create notebook dialog --- apps/web/src/views/Notebooks.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index d2815cc1e..c3f433e30 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -42,26 +42,6 @@ const Notebooks = props => { onClick: async () => setOpen(true) }} /> - { - if ( - await db.notebooks.add({ - title, - description, - topics - }) - ) { - //setNotebooks(db.notebooks.all); - setOpen(false); - } else { - showSnack("Please fill out the notebook title."); - } - }} - close={() => { - setOpen(false); - }} - /> ); }; From b9eb241ab511ecb3c703a0ba79a182d9c5edba74 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 11:14:13 +0500 Subject: [PATCH 005/394] refactor: move createnbdialog to its own file --- .../components/dialogs/add-notebook-dialog.js | 129 ++++++++++++++++++ apps/web/src/components/dialogs/dialog.js | 117 ++++++++++++++++ apps/web/src/components/dialogs/index.js | 106 ++------------ apps/web/src/views/Notebooks.js | 11 +- 4 files changed, 263 insertions(+), 100 deletions(-) create mode 100644 apps/web/src/components/dialogs/add-notebook-dialog.js create mode 100644 apps/web/src/components/dialogs/dialog.js diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js new file mode 100644 index 000000000..cadb862d5 --- /dev/null +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -0,0 +1,129 @@ +import React from "react"; +import { Flex, Box, Text, Button as RebassButton } from "rebass"; +import { Input, Checkbox, Label } from "@rebass/forms"; +import * as Icon from "react-feather"; +import Dialog, { showDialog } from "./dialog"; +import { showSnack } from "../snackbar"; + +export default class AddNotebookDialog extends React.Component { + title = []; + description = []; + _inputRefs = []; + lastLength = 0; + state = { + topics: [], + open: false + }; + + addTopic(index) { + this.setState({ topics: this.state.topics.splice(index + 1, 0, "") }, () => + setTimeout(() => { + this._inputRefs[index + 1].focus(); + }, 0) + ); + } + + render() { + const props = this.props; + return ( + + (this.title = e.target.value)} + placeholder="Enter name" + /> + (this.description = e.target.value)} + placeholder="Enter description (optional)" + /> + + + Topics (optional): + + + {this.topics.map((value, index) => ( + + (this._inputRefs[index] = ref)} + variant="default" + value={this.topics[index]} + placeholder="Topic name" + onFocus={e => { + this.lastLength = e.nativeEvent.target.value.length; + }} + onChange={e => { + const { topics } = this.state; + topics[index] = e.target.value; + this.setState({ + topics + }); + }} + onKeyUp={e => { + if (e.nativeEvent.key === "Enter") { + this.addTopic(index); + } else if ( + e.nativeEvent.key === "Backspace" && + this.lastLength === 0 && + index > 0 + ) { + this.setState( + { + topics: this.state.topics.splice(index, 1) + }, + () => { + setTimeout(() => { + this._inputRefs[index - 1].focus(); + }, 0); + } + ); + } + this.lastLength = e.nativeEvent.target.value.length; + }} + /> + this.addTopic(index)} + > + + + + + + ))} + + + } + positiveButton={{ + text: "Add", + click: () => { + if (!this.title.trim().length) + return showSnack("Please enter the notebook title."); + props.onDone({ + title: this.title, + description: this.description, + topics: this.state.topics + }); + } + }} + negativeButton={{ text: "Cancel", click: props.close }} + /> + ); + } +} diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js new file mode 100644 index 000000000..ea041d8ef --- /dev/null +++ b/apps/web/src/components/dialogs/dialog.js @@ -0,0 +1,117 @@ +import React, { useState, useEffect } from "react"; +import ReactDOM from "react-dom"; +import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; +import { Input, Checkbox, Label } from "@rebass/forms"; +import * as Icon from "react-feather"; +import { ThemeProvider } from "../../utils/theme"; +import { db } from "../../common"; +import Modal from "react-modal"; + +export default class Dialog extends React.Component { + render() { + const props = this.props; + return ( + + {theme => ( + + + + + + + + {props.title} + + + {props.content} + + {props.positiveButton && ( + + {props.positiveButton.text || "OK"} + + )} + + {props.negativeButton && ( + + {props.negativeButton.text || "Cancel"} + + )} + + + + )} + + ); + } +} + +export const showDialog = dialog => { + const root = document.getElementById("dialogContainer"); + const perform = (resolve, result) => { + ReactDOM.unmountComponentAtNode(root); + resolve(result); + }; + if (root) { + return new Promise(resolve => { + const PropDialog = dialog(perform.bind(this, resolve)); + ReactDOM.render(, root); + }); + } + return Promise.reject("No element with id 'dialogContainer'"); +}; diff --git a/apps/web/src/components/dialogs/index.js b/apps/web/src/components/dialogs/index.js index 64c2c0c44..e2f0bd1be 100644 --- a/apps/web/src/components/dialogs/index.js +++ b/apps/web/src/components/dialogs/index.js @@ -3,106 +3,15 @@ import ReactDOM from "react-dom"; import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; import { Input, Checkbox, Label } from "@rebass/forms"; import * as Icon from "react-feather"; -import { ThemeProvider } from "../../utils/theme"; import { db } from "../../common"; -import Modal from "react-modal"; +import Dialog, { showDialog } from "./dialog"; -const Dialog = props => { - const [open, setOpen] = useState(false); - Dialog.close = () => setOpen(false); - useEffect(() => { - setOpen(props.open); - }, [props.open]); - - return ( - - {theme => ( - - - - - - - - {props.title} - - - {props.content} - - {props.positiveButton && ( - - {props.positiveButton.text || "OK"} - - )} - - {props.negativeButton && ( - - {props.negativeButton.text || "Cancel"} - - )} - - - - )} - - ); -}; +/* import React, { useState, useEffect } from "react"; +import ReactDOM from "react-dom"; +import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; +import { Input, Checkbox, Label } from "@rebass/forms"; +import * as Icon from "react-feather"; +import { db } from "../../common"; const inputRefs = []; export const CreateNotebookDialog = props => { @@ -492,3 +401,4 @@ export const moveNote = (noteId, notebook) => { } return Promise.reject("No element with id 'dialogContainer'"); }; + */ diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index c3f433e30..80604314a 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -3,14 +3,14 @@ import { Flex } from "rebass"; import { db, ev } from "../common"; import { showSnack } from "../components/snackbar"; import Notebook from "../components/notebook"; -import { CreateNotebookDialog } from "../components/dialogs"; +import AddNotebookDialog from "../components/dialogs/addnotebookdialog"; import ListContainer from "../components/list-container"; import useStore from "../common/store"; const Notebooks = props => { const [open, setOpen] = useState(false); const notebooks = useStore(state => state.notebooks); - + const addNotebook = useStore(state => state.addNotebook); return ( <> { onClick: async () => setOpen(true) }} /> + { + setOpen(false); + }} + /> ); }; From 770f36f65132da560b6ce37c5e407adb4f2a3e76 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 11:17:23 +0500 Subject: [PATCH 006/394] refactor: remove unused imports --- apps/web/src/views/Notebooks.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 80604314a..0d4a6807a 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -1,7 +1,6 @@ import React, { useState, useEffect } from "react"; import { Flex } from "rebass"; -import { db, ev } from "../common"; -import { showSnack } from "../components/snackbar"; +import { db } from "../common"; import Notebook from "../components/notebook"; import AddNotebookDialog from "../components/dialogs/addnotebookdialog"; import ListContainer from "../components/list-container"; From 213a15ce09542e8f2eceaa1990668290fe6469e8 Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Sat, 22 Feb 2020 11:21:17 +0500 Subject: [PATCH 007/394] fix: sync favorite & pin state between properties and navigator (#11) * fix: properties and note favorite synced correctly * to do list * fixed: added pin sync and removed onClick error * fix: removed save * fix: removd comment --- apps/web/src/components/editor/index.js | 18 ++++++++++++++++-- apps/web/src/components/note/index.js | 20 ++++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index c15930ba9..2b5b5d903 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -82,12 +82,26 @@ export default class Editor extends React.Component { ev.addListener("onNewNote", this.onNewNote.bind(this)); ev.addListener("onOpenNote", this.onOpenNote.bind(this)); ev.addListener("onClearNote", this.onClearNote.bind(this)); + ev.addListener("onNoteFavorited", this.onNoteFavorite.bind(this)); + ev.addListener("onNotePinned", this.onNotePin.bind(this)); } componentWillUnmount() { ev.removeListener("onNewNote", this.onNewNote.bind(this)); ev.removeListener("onOpenNote", this.onOpenNote.bind(this)); ev.removeListener("onClearNote", this.onClearNote.bind(this)); + ev.removeListener("onNoteFavorited", this.onNoteFavorite.bind(this)); + ev.removeListener("onNotePinned", this.onNotePin.bind(this)); + } + + onNoteFavorite(favorite, id) { + if (id && id !== this.id) return; + this.setState({ favorite }); + } + + onNotePin(pinned, id) { + if (id && id !== this.id) return; + this.setState({ pinned }); } onNewNote(show = true, cb = null) { @@ -142,8 +156,8 @@ export default class Editor extends React.Component { content, title: this.title, id: this.id, - favorite: this.favorite, - pinned: this.pinned, + favorite: this.state.favorite, + pinned: this.state.pinned, colors: this.state.colors //TODO add tags once the database is done }; diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index c9923d223..47bf1c7bd 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -20,25 +20,29 @@ const menuItems = note => [ }, { title: note.pinned ? "Unpin" : "Pin", - onClick: async () => + onClick: async () => { db.notes .note(note.id) .pin() .then(() => { showSnack("Note pinned!", Icon.Check); ev.emit("refreshNotes"); - }) + }); + sendNotePinnedEvent(note.pinned, note.id); + } }, { title: note.favorite ? "Unfavorite" : "Favorite", - onClick: async () => + onClick: async () => { db.notes .note(note.id) .favorite() .then(() => { showSnack("Note favorited!", Icon.Check); ev.emit("refreshNotes"); - }) + }); + sendNoteFavoriteEvent(note.favorite, note.id); + } }, { title: "Edit" }, { title: note.locked ? "Remove lock" : "Lock" }, //TODO @@ -74,6 +78,14 @@ function sendOpenNoteEvent(note) { ev.emit("onOpenNote", note); } +function sendNoteFavoriteEvent(favorite, id) { + ev.emit("onNoteFavorited", favorite, id); +} + +function sendNotePinnedEvent(pinned, id) { + ev.emit("onNotePinned", pinned, id); +} + const Note = ({ item, index }) => { const note = item; return note ? ( From ea68dc1ab81948209200abd48949fcb7b367fc93 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Date: Sat, 22 Feb 2020 12:52:09 +0500 Subject: [PATCH 008/394] feat: add tags (#13) * Fix empty tags being added * Feat: Add tagging * Fix incorrect usage of useState() * Clean up * refactor: remove console.log Co-authored-by: Abdullah Atta --- apps/web/src/components/editor/index.js | 16 +++--- apps/web/src/components/list-item/index.js | 2 +- apps/web/src/components/properties/index.js | 4 +- apps/web/src/navigation/navigators/index.js | 1 + .../navigation/navigators/rootnavigator.js | 4 +- .../src/navigation/navigators/tagnavigator.js | 12 +++++ apps/web/src/views/Tags.js | 53 +++++++++++++++++++ apps/web/src/views/index.js | 2 + apps/web/yarn.lock | 2 +- 9 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 apps/web/src/navigation/navigators/tagnavigator.js create mode 100644 apps/web/src/views/Tags.js diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index 2b5b5d903..36618dfb5 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -134,10 +134,12 @@ export default class Editor extends React.Component { this.titleRef.value = note.title; this.pinned = note.pinned; this.favorite = note.favorite; + this.tags = note.tags; this.setState({ pinned: this.pinned, favorite: this.favorite, - colors: note.colors + colors: note.colors, + tags: note.tags }); let delta = await dbNote.delta(); this.quill.setContents(delta); @@ -156,10 +158,10 @@ export default class Editor extends React.Component { content, title: this.title, id: this.id, - favorite: this.state.favorite, - pinned: this.state.pinned, - colors: this.state.colors - //TODO add tags once the database is done + favorite: this.favorite, + pinned: this.pinned, + colors: this.state.colors, + //tags: this.state.tags }; return await db.notes.add(note); } @@ -234,7 +236,7 @@ export default class Editor extends React.Component { this.setState({ colors }); }} tags={this.state.tags} - addTag={tag => { + addTag={async tag => { let tags = [...this.state.tags]; if (tags.includes(tag)) { tags.splice(tags.indexOf(tag), 1); @@ -242,6 +244,8 @@ export default class Editor extends React.Component { tags[this.state.tags.length] = tag; } this.setState({ tags }); + if (this.id) + await db.notes.note(this.id).tag(tag); }} onLocked={state => {}} /> diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 822342797..b489e3da4 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -67,7 +67,7 @@ const ListItem = props => ( }} > - + {props.title} diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index c171740a8..e4e8e007a 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -92,7 +92,9 @@ const Properties = props => { event.key === " " || event.key === "," ) { - props.addTag && props.addTag(event.target.value); + props.addTag && + event.target.value && + props.addTag(event.target.value); event.target.value = ""; } }} diff --git a/apps/web/src/navigation/navigators/index.js b/apps/web/src/navigation/navigators/index.js index 09f5d9fbc..a31df07b9 100644 --- a/apps/web/src/navigation/navigators/index.js +++ b/apps/web/src/navigation/navigators/index.js @@ -1,3 +1,4 @@ export const NotebookNavigator = require("./nbnavigator").default; export const RootNavigator = require("./rootnavigator").default; export const SettingsNavigator = require("./settingnavigator").default; +export const TagNavigator = require("./tagnavigator").default; diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index ec34de42a..ced8cc685 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -3,7 +3,8 @@ import { SettingsContainer, Favorites, Trash, - NotebooksContainer + NotebooksContainer, + TagsContainer } from "../../views"; import * as Icon from "react-feather"; import { @@ -50,6 +51,7 @@ const routes = { }), ...createNormalRoute("favorites", Favorites, Icon.Star), ...createNormalRoute("trash", Trash, Icon.Trash2), + ...createRoute("tags", TagsContainer, { icon: Icon.Tag }), ...colorRoutes, ...bottomRoutes }; diff --git a/apps/web/src/navigation/navigators/tagnavigator.js b/apps/web/src/navigation/navigators/tagnavigator.js new file mode 100644 index 000000000..1dd507db5 --- /dev/null +++ b/apps/web/src/navigation/navigators/tagnavigator.js @@ -0,0 +1,12 @@ +import { Notes, Tags } from "../../views"; +import Navigator from "../index"; +import { createRoute } from "../routes"; + +const routes = { + ...createRoute("tags", Tags, { title: "Tags" }), + ...createRoute("notes", Notes) +}; +const TagNavigator = new Navigator("TagNavigator", routes, { + backButtonEnabled: true +}); +export default TagNavigator; diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js new file mode 100644 index 000000000..c22f58310 --- /dev/null +++ b/apps/web/src/views/Tags.js @@ -0,0 +1,53 @@ +import React, { useEffect } from "react"; +import { Flex, Text } from "rebass"; +import ListContainer from "../components/list-container"; +import ListItem from "../components/list-item"; +import { db } from "../common"; + +const TagNode = ({ title }) => ( + + + {"#"} + + {title} + +); + +const Tags = props => { + const tags = db.tags.all; + return ( + ( + } + onClick={() => { + const notesOfTag = db.notes.tagged(tags[index].title); + props.navigator.navigate("notes", { + notes: notesOfTag + }); + }} + /> + )} + /> + ); +}; + +const TagsContainer = () => { + useEffect(() => { + const TagNavigator = require("../navigation/navigators/tagnavigator") + .default; + if (!TagNavigator.restore()) { + TagNavigator.navigate("tags"); + } + }, []); + return ( + + ); +}; + +export { Tags, TagsContainer }; diff --git a/apps/web/src/views/index.js b/apps/web/src/views/index.js index a56716eb3..e154ca716 100644 --- a/apps/web/src/views/index.js +++ b/apps/web/src/views/index.js @@ -10,3 +10,5 @@ export const Account = require("./Account").default; export const SettingsContainer = require("./Settings").SettingsContainer; export const General = require("./General").default; export const TOS = require("./TOS").default; +export const Tags = require("./Tags").Tags; +export const TagsContainer = require("./Tags").TagsContainer; diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 83d27f8e7..0a35a5c06 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7020,7 +7020,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@https://github.com/thecodrr/notes-core.git": version "1.1.0" - resolved "https://github.com/thecodrr/notes-core.git#e591bdeff6852a104ff0db86a0235a95dfbd1fa3" + resolved "https://github.com/thecodrr/notes-core.git#5fe97a7017c58d6cbba29cbfb59876be72c53e8b" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From c335697263af6aae4c94fc5eb4f6cfef48d871c5 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 13:46:24 +0500 Subject: [PATCH 009/394] refactor: clean up dialogs --- apps/web/src/common/store.js | 2 +- .../components/dialogs/add-notebook-dialog.js | 4 +- apps/web/src/components/dialogs/confirm.js | 35 ++ apps/web/src/components/dialogs/dialog.js | 4 +- apps/web/src/components/dialogs/index.js | 404 ------------------ .../web/src/components/dialogs/logindialog.js | 39 ++ .../components/dialogs/move-note-dialog.js | 196 +++++++++ apps/web/src/components/note/index.js | 10 +- .../navigation/navigators/rootnavigator.js | 4 +- apps/web/src/views/Favorites.js | 6 +- apps/web/src/views/Trash.js | 6 +- 11 files changed, 288 insertions(+), 422 deletions(-) create mode 100644 apps/web/src/components/dialogs/confirm.js delete mode 100644 apps/web/src/components/dialogs/index.js create mode 100644 apps/web/src/components/dialogs/logindialog.js create mode 100644 apps/web/src/components/dialogs/move-note-dialog.js diff --git a/apps/web/src/common/store.js b/apps/web/src/common/store.js index 70d1e0714..7ac8b3201 100644 --- a/apps/web/src/common/store.js +++ b/apps/web/src/common/store.js @@ -2,7 +2,7 @@ import { db } from "./index"; import create from "zustand"; const [useStore] = create(set => ({ - notebooks: db.notebooks.all, + notebooks: [], addNotebook: async notebook => { if (await db.notebooks.add(notebook)) { set({ notebooks: db.notebooks.all }); diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index cadb862d5..4fa3b4805 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -112,7 +112,7 @@ export default class AddNotebookDialog extends React.Component { } positiveButton={{ text: "Add", - click: () => { + onClick: () => { if (!this.title.trim().length) return showSnack("Please enter the notebook title."); props.onDone({ @@ -122,7 +122,7 @@ export default class AddNotebookDialog extends React.Component { }); } }} - negativeButton={{ text: "Cancel", click: props.close }} + negativeButton={{ text: "Cancel", onClick: props.close }} /> ); } diff --git a/apps/web/src/components/dialogs/confirm.js b/apps/web/src/components/dialogs/confirm.js new file mode 100644 index 000000000..41c65322e --- /dev/null +++ b/apps/web/src/components/dialogs/confirm.js @@ -0,0 +1,35 @@ +import React from "react"; +import { Box, Text } from "rebass"; +import Dialog, { showDialog } from "./dialog"; + +function Confirm(props) { + return ( + + {props.message} + + } + positiveButton={{ + text: "Yes", + onClick: props.onYes + }} + negativeButton={{ text: "No", onClick: props.onNo }} + /> + ); +} + +export const confirm = (icon, title, message) => { + return showDialog(perform => ( + perform(false)} + onYes={() => perform(true)} + /> + )); +}; diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index ea041d8ef..02137fbf4 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -77,7 +77,7 @@ export default class Dialog extends React.Component { mx={1} width={"25%"} disabled={props.positiveButton.disabled || false} - onClick={props.positiveButton.click} + onClick={props.positiveButton.onClick} > {props.positiveButton.text || "OK"} @@ -110,7 +110,7 @@ export const showDialog = dialog => { if (root) { return new Promise(resolve => { const PropDialog = dialog(perform.bind(this, resolve)); - ReactDOM.render(, root); + ReactDOM.render(PropDialog, root); }); } return Promise.reject("No element with id 'dialogContainer'"); diff --git a/apps/web/src/components/dialogs/index.js b/apps/web/src/components/dialogs/index.js deleted file mode 100644 index e2f0bd1be..000000000 --- a/apps/web/src/components/dialogs/index.js +++ /dev/null @@ -1,404 +0,0 @@ -import React, { useState, useEffect } from "react"; -import ReactDOM from "react-dom"; -import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; -import { Input, Checkbox, Label } from "@rebass/forms"; -import * as Icon from "react-feather"; -import { db } from "../../common"; -import Dialog, { showDialog } from "./dialog"; - -/* import React, { useState, useEffect } from "react"; -import ReactDOM from "react-dom"; -import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; -import { Input, Checkbox, Label } from "@rebass/forms"; -import * as Icon from "react-feather"; -import { db } from "../../common"; - -const inputRefs = []; -export const CreateNotebookDialog = props => { - const [topics, setTopics] = useState([""]); - const addTopic = index => { - topics.splice(index + 1, 0, ""); - setTopics([...topics]); - setTimeout(() => { - inputRefs[index + 1].focus(); - }, 0); - }; - return ( - - (CreateNotebookDialog.title = e.target.value)} - placeholder="Enter name" - /> - (CreateNotebookDialog.description = e.target.value)} - placeholder="Enter description (optional)" - /> - - - Topics (optional): - - - {topics.map((value, index) => ( - - (inputRefs[index] = ref)} - variant="default" - value={topics[index]} - placeholder="Topic name" - onFocus={e => { - CreateNotebookDialog.lastLength = - e.nativeEvent.target.value.length; - }} - onChange={e => { - topics[index] = e.target.value; - setTopics([...topics]); - }} - onKeyUp={e => { - if (e.nativeEvent.key === "Enter") { - addTopic(index); - } else if ( - e.nativeEvent.key === "Backspace" && - CreateNotebookDialog.lastLength === 0 && - index > 0 - ) { - topics.splice(index, 1); - setTopics([...topics]); - setTimeout(() => { - inputRefs[index - 1].focus(); - }, 0); - } - CreateNotebookDialog.lastLength = - e.nativeEvent.target.value.length; - }} - /> - addTopic(index)} - > - - - - - - ))} - - - } - positiveButton={{ - text: "Done", - click: () => - props.onDone( - topics, - CreateNotebookDialog.title, - CreateNotebookDialog.description - ) - }} - negativeButton={{ text: "Cancel", click: props.close }} - /> - ); -}; - -const ConfirmationDialog = props => ( - - {props.message} - - } - positiveButton={{ - text: "Yes", - click: props.onYes - }} - negativeButton={{ text: "No", click: props.onNo }} - /> -); - -const LoginDialog = props => ( - - - - - - - - - - } - /> -); - -export const showSignInDialog = (icon, title, message) => { - const root = document.getElementById("dialogContainer"); - const perform = (result, resolve) => { - Dialog.close(); - ReactDOM.unmountComponentAtNode(root); - resolve(result); - }; - if (root) { - return new Promise((resolve, _) => { - ReactDOM.render( - { - perform(false, resolve); - }} - title={title} - message={message} - icon={icon} - />, - root - ); - }); - } - return Promise.reject("No element with id 'dialogContainer'"); -}; - -export const ask = (icon, title, message) => { - const root = document.getElementById("dialogContainer"); - const perform = (result, resolve) => { - Dialog.close(); - ReactDOM.unmountComponentAtNode(root); - resolve(result); - }; - if (root) { - return new Promise((resolve, _) => { - ReactDOM.render( - perform(false, resolve)} - onYes={() => perform(true, resolve)} - />, - root - ); - }); - } - return Promise.reject("No element with id 'dialogContainer'"); -}; - -export const MoveDialog = props => { - const [items, setItems] = useState(db.notebooks.all); - const [type, setType] = useState("notebooks"); - const [title, setTitle] = useState("Notebooks"); - const [mode, setMode] = useState("read"); - useEffect(() => { - MoveDialog.last = []; - }, []); - return ( - - - - {type !== "notebooks" && ( - { - let item = MoveDialog.last.pop(); - setType(item.type); - setTitle(item.title); - setItems(item.items); - }} - sx={{ - ":hover": { color: "primary" }, - marginRight: 2 - }} - > - - - )} - {title} - - {type !== "notes" && ( - { - if (mode === "write") { - setMode("read"); - return; - } - setMode("write"); - setTimeout(() => { - MoveDialog.inputRef.focus(); - }, 0); - }} - sx={{ - ":hover": { color: "primary" } - }} - > - {mode === "read" ? : } - - )} - - (MoveDialog.inputRef = ref)} - variant="default" - sx={{ display: mode === "write" ? "block" : "none" }} - my={1} - placeholder={type === "notebooks" ? "Notebook name" : "Topic name"} - onKeyUp={async e => { - if (e.nativeEvent.key === "Enter" && e.target.value.length > 0) { - if (type === "notebooks") { - await db.notebooks.add({ - title: e.target.value - }); - setItems(db.notebooks.all); - } else { - await db.notebooks - .notebook(MoveDialog.notebook.id) - .topics.add(e.target.value); - setItems( - db.notebooks.notebook(MoveDialog.notebook.id).topics - ); - } - MoveDialog.inputRef.value = ""; - setMode("read"); - } - }} - /> - - {items.length ? ( - items.map(v => { - return ( - { - MoveDialog.last.push({ - title: title, - items: items, - type: type - }); - if (type === "notebooks") { - setType("topics"); - MoveDialog.notebook = v; - setTitle(v.title); - setItems(v.topics); - } else if (type === "topics") { - setType("notes"); - MoveDialog.topic = v.title; - setTitle(`${MoveDialog.notebook.title} - ${v.title}`); - setItems( - db.notebooks - .notebook(MoveDialog.notebook.id) - .topics.topic(v.title).all - ); - } - }} - > - {v.title} - {v.totalNotes !== undefined && ( - - {v.totalNotes + " Notes"} - - )} - - ); - }) - ) : ( - - Nothing here - - )} - - - } - positiveButton={{ - text: "Move", - click: async () => { - try { - await db.notes.move( - { id: MoveDialog.notebook.id, topic: MoveDialog.topic }, - props.noteId - ); - props.onMove(); - } catch (e) { - console.log(e); - } finally { - props.onClose(); - } - }, - disabled: type !== "notes" - }} - negativeButton={{ text: "Cancel", onClick: props.onClose }} - /> - ); -}; - -export const moveNote = (noteId, notebook) => { - const root = document.getElementById("dialogContainer"); - const perform = (result, resolve) => { - Dialog.close(); - ReactDOM.unmountComponentAtNode(root); - resolve(result); - }; - if (root) { - return new Promise((resolve, _) => { - ReactDOM.render( - perform(false, resolve)} - onMove={() => perform(true, resolve)} - />, - root - ); - }); - } - return Promise.reject("No element with id 'dialogContainer'"); -}; - */ diff --git a/apps/web/src/components/dialogs/logindialog.js b/apps/web/src/components/dialogs/logindialog.js new file mode 100644 index 000000000..60bd66f24 --- /dev/null +++ b/apps/web/src/components/dialogs/logindialog.js @@ -0,0 +1,39 @@ +import React, { useState, useEffect } from "react"; +import ReactDOM from "react-dom"; +import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; +import { Input, Checkbox, Label } from "@rebass/forms"; +import * as Icon from "react-feather"; +import { db } from "../../common"; +import Dialog, { showDialog } from "./dialog"; + +const LoginDialog = props => ( + + + + + + + + + + } + /> +); + +export const showLogInDialog = () => { + return showDialog(perform => perform(false)} />); +}; diff --git a/apps/web/src/components/dialogs/move-note-dialog.js b/apps/web/src/components/dialogs/move-note-dialog.js new file mode 100644 index 000000000..72adba520 --- /dev/null +++ b/apps/web/src/components/dialogs/move-note-dialog.js @@ -0,0 +1,196 @@ +import React from "react"; +import { Flex, Box, Text } from "rebass"; +import { Input } from "@rebass/forms"; +import * as Icon from "react-feather"; +import { db } from "../../common"; +import Dialog, { showDialog } from "./dialog"; + +export default class MoveDialog extends React.Component { + history = []; + _inputRef; + selectedNotebook; + selectedTopic; + state = { + items: [], + type: "notebooks", + title: "Notebooks", + mode: "read" + }; + + render() { + const { items, type, title, mode } = this.state; + const props = this.props; + return ( + + + + { + let item = this.history.pop(); + this.setState({ ...item }); + }} + sx={{ + display: this.history.length ? "block" : "none", + ":hover": { color: "primary" }, + marginRight: 2 + }} + > + + + {title} + + { + if (mode === "write") { + this.setState({ mode: "read" }); + return; + } + this.setState({ mode: "write" }); + setTimeout(() => { + this._inputRef.focus(); + }, 0); + }} + sx={{ + display: type === "notes" ? "none" : "block", + ":hover": { color: "primary" } + }} + > + {mode === "read" ? : } + + + (this._inputRef = ref)} + variant="default" + sx={{ display: mode === "write" ? "block" : "none" }} + my={1} + placeholder={ + type === "notebooks" ? "Notebook name" : "Topic name" + } + onKeyUp={async e => { + if ( + e.nativeEvent.key === "Enter" && + e.target.value.length > 0 + ) { + if (type === "notebooks") { + await db.notebooks.add({ + title: e.target.value + }); + this.setState({ items: db.notebooks.all }); + } else { + await db.notebooks + .notebook(MoveDialog.notebook.id) + .topics.add(e.target.value); + this.setState({ + items: db.notebooks.notebook(MoveDialog.notebook.id) + .topics + }); + } + this._inputRef.value = ""; + this.setState({ mode: "read" }); + } + }} + /> + + {items.length ? ( + items.map(item => { + return ( + { + this.history.push({ + title, + items, + type + }); + if (type === "notebooks") { + this.setState({ + type: "topics", + items: item.topics, + title: item.title + }); + this.selectedNotebook = item; + } else if (type === "topics") { + this.setState({ + type: "notes", + title: `${this.selectedNotebook.title} - ${item.title}`, + items: db.notebooks + .notebook(this.notebook.id) + .topics.topic(item.title).all + }); + this.selectedTopic = item.title; + } + }} + > + {item.title} + {item.totalNotes !== undefined && ( + + {item.totalNotes + " Notes"} + + )} + + ); + }) + ) : ( + + Nothing here + + )} + + + } + positiveButton={{ + text: "Move", + click: async () => { + try { + await db.notes.move( + { id: this.selectedNotebook.id, topic: this.selectedTopic }, + props.noteId + ); + props.onMove(); + } catch (e) { + console.log(e); + } finally { + props.onClose(); + } + }, + disabled: type !== "notes" + }} + negativeButton={{ text: "Cancel", onClick: props.onClose }} + /> + ); + } +} + +export const showMoveNoteDialog = (noteId, notebook) => { + return showDialog(perform => ( + perform(false)} + onMove={() => perform(true)} + /> + )); +}; diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index c9923d223..b4db57e47 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -5,15 +5,15 @@ import TimeAgo from "timeago-react"; import { db, ev } from "../../common"; import { showSnack } from "../snackbar"; import ListItem from "../list-item"; -import { ask, moveNote } from "../dialogs"; +import { confirm } from "../dialogs/confirm"; +import { showMoveNoteDialog } from "../dialogs/movenotedialog"; const dropdownRefs = []; const menuItems = note => [ { title: note.notebook ? "Move" : "Add to", onClick: async () => { - console.log(note.id, note.notebook); - if (await moveNote(note.id, note.notebook)) { + if (await showMoveNoteDialog(note.id)) { showSnack("Note moved successfully!"); } } @@ -47,10 +47,10 @@ const menuItems = note => [ title: "Move to Trash", color: "red", onClick: () => { - ask( + confirm( Icon.Trash2, "Delete", - "Are you sure you want to move this note to Trash? It will be moved to Trash and permanently deleted after 7 days." + "Are you sure you want to delete this note?" ).then(res => { if (res) { ev.emit("onClearNote", note.id); diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index ec34de42a..80e548aa7 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -13,7 +13,7 @@ import { createDeadRoute } from "../routes"; import Navigator from "../index"; -import { showSignInDialog } from "../../components/dialogs"; +import { showLogInDialog } from "../../components/dialogs/logindialog"; import { changeTheme, isDarkTheme } from "../../utils/theme"; /*For color Search*/ @@ -34,7 +34,7 @@ const bottomRoutes = { isToggled: () => isDarkTheme() }), ...createDeadRoute("signin", Icon.LogIn, { - onClick: () => showSignInDialog(Icon.LogIn, "Login", ""), + onClick: () => showLogInDialog(), bottom: true }), ...createRoute("settings", SettingsContainer, { diff --git a/apps/web/src/views/Favorites.js b/apps/web/src/views/Favorites.js index 3adea2c24..8a7af2481 100644 --- a/apps/web/src/views/Favorites.js +++ b/apps/web/src/views/Favorites.js @@ -3,13 +3,13 @@ import { db, ev } from "../common"; import * as Icon from "react-feather"; import ListView from "../components/listview"; import { showSnack } from "../components/snackbar"; -import { ask } from "../components/dialogs"; +import { confirm } from "../components/dialogs/confirm"; const dropdownRefs = []; const menuItems = item => [ { title: "Unfavorite", onClick: async () => { - ask( + confirm( Icon.Star, "Unfavorite", "Are you sure you want to remove this item from favorites?" @@ -33,7 +33,7 @@ const menuItems = item => [ title: "Delete", color: "red", onClick: async () => { - ask( + confirm( Icon.Trash2, "Delete", "Are you sure you want to delete this note? It will be moved to trash and permanently deleted after 7 days." diff --git a/apps/web/src/views/Trash.js b/apps/web/src/views/Trash.js index 615373a1a..6b2894e0c 100644 --- a/apps/web/src/views/Trash.js +++ b/apps/web/src/views/Trash.js @@ -2,7 +2,7 @@ import React from "react"; import { db, ev } from "../common"; import * as Icon from "react-feather"; import ListView from "../components/listview"; -import { ask } from "../components/dialogs"; +import { confirm } from "../components/dialogs/confirm"; import { showSnack } from "../components/snackbar"; const dropdownRefs = []; @@ -10,7 +10,7 @@ const menuItems = item => [ { title: "Restore", onClick: async () => { - ask( + confirm( Icon.Star, "Restore", `Are you sure you want to restore this item to ${item.type}?` @@ -28,7 +28,7 @@ const menuItems = item => [ title: "Delete", color: "red", onClick: async () => { - ask( + confirm( Icon.Star, "Delete", `Are you sure you want to permanently delete this item?` From 723613771b394e8463f04764bb74a09d87bdea99 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 14:24:53 +0500 Subject: [PATCH 010/394] fix: initialize state on app launch --- apps/web/src/app.js | 19 +++++++++---------- apps/web/src/common/store.js | 7 +++++++ .../components/dialogs/add-notebook-dialog.js | 8 ++++---- apps/web/src/components/dialogs/dialog.js | 2 +- apps/web/src/views/Notebooks.js | 2 +- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index e7c08b0b3..a3fc5dfca 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -8,6 +8,7 @@ import "./app.css"; import { usePersistentState } from "./utils/hooks"; import { ev } from "./common"; import { useTheme } from "emotion-theming"; +import useStore from "./common/store"; const NavMenuItem = props => { const [fill, setFill] = useState(); @@ -75,17 +76,15 @@ function App() { 0 ); const [show, setShow] = usePersistentState("navContainerState", true); - const [sideMenuOpen, setSideMenuOpen] = useState(false); + const initStore = useStore(state => state.init); + const isSideMenuOpen = useStore(state => state.isSideMenuOpen); + useEffect(() => { + initStore(); + }, [initStore]); + useEffect(() => { RootNavigator.navigate(Object.keys(RootNavigator.routes)[selectedIndex]); - function openSideMenu() { - setSideMenuOpen(true); - } - ev.addListener("openSideMenu", openSideMenu); - return () => { - ev.removeListener("openSideMenu", openSideMenu); - }; - }); + }, []); return ( ({ + init: () => { + console.log("initializing state..."); + set({ + notebooks: db.notebooks.all + }); + }, notebooks: [], + isSideMenuOpen: false, addNotebook: async notebook => { if (await db.notebooks.add(notebook)) { set({ notebooks: db.notebooks.all }); diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index 4fa3b4805..1e1e15701 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -2,7 +2,7 @@ import React from "react"; import { Flex, Box, Text, Button as RebassButton } from "rebass"; import { Input, Checkbox, Label } from "@rebass/forms"; import * as Icon from "react-feather"; -import Dialog, { showDialog } from "./dialog"; +import Dialog from "./dialog"; import { showSnack } from "../snackbar"; export default class AddNotebookDialog extends React.Component { @@ -27,7 +27,7 @@ export default class AddNotebookDialog extends React.Component { const props = this.props; return ( - {this.topics.map((value, index) => ( + {this.state.topics.map((value, index) => ( (this._inputRefs[index] = ref)} variant="default" - value={this.topics[index]} + value={this.state.topics[index]} placeholder="Topic name" onFocus={e => { this.lastLength = e.nativeEvent.target.value.length; diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index 02137fbf4..10ba57c91 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -14,7 +14,7 @@ export default class Dialog extends React.Component { {theme => ( { ); }; -const NotebooksContainer = props => { +const NotebooksContainer = () => { useEffect(() => { const NotebookNavigator = require("../navigation/navigators/nbnavigator") .default; From 83180fb9a5d9abbaf4100ee850156d3efe2f878e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 14:37:50 +0500 Subject: [PATCH 011/394] refactor: remove unused imports --- apps/web/src/app.js | 8 ++------ apps/web/src/common/index.js | 1 - apps/web/src/components/checkbox/index.js | 1 - apps/web/src/components/dialogs/dialog.js | 7 ++----- apps/web/src/components/dialogs/logindialog.js | 8 +++----- apps/web/src/components/listview/index.js | 1 - apps/web/src/views/Home.js | 2 +- apps/web/src/views/Notes.js | 1 - apps/web/src/views/Settings.js | 2 +- 9 files changed, 9 insertions(+), 22 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index a3fc5dfca..374ee0304 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -6,7 +6,6 @@ import { ThemeProvider } from "./utils/theme"; import RootNavigator from "./navigation/navigators/rootnavigator"; import "./app.css"; import { usePersistentState } from "./utils/hooks"; -import { ev } from "./common"; import { useTheme } from "emotion-theming"; import useStore from "./common/store"; @@ -66,10 +65,6 @@ const NavMenuItem = props => { var startX, startWidth; -function getNavigationViewWidth() { - return window.localStorage.getItem("navigationViewWidth"); -} - function App() { const [selectedIndex, setSelectedIndex] = usePersistentState( "navSelectedIndex", @@ -84,6 +79,7 @@ function App() { useEffect(() => { RootNavigator.navigate(Object.keys(RootNavigator.routes)[selectedIndex]); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( @@ -199,7 +195,7 @@ function App() { let view = document.querySelector(".RootNavigator"); view.style.width = `${startWidth + e.clientX - startX}px`; }} - onDragEnd={e => { + onDragEnd={() => { let view = document.querySelector(".RootNavigator"); view.style.width = view.getBoundingClientRect().width; window.localStorage.setItem( diff --git a/apps/web/src/common/index.js b/apps/web/src/common/index.js index f68333dd2..d1e572183 100644 --- a/apps/web/src/common/index.js +++ b/apps/web/src/common/index.js @@ -4,7 +4,6 @@ import events from "events"; export const db = new Database(StorageInterface); export const ev = new events.EventEmitter(); -console.log("from common", db); export function sendNewNoteEvent() { ev.emit("onNewNote"); } diff --git a/apps/web/src/components/checkbox/index.js b/apps/web/src/components/checkbox/index.js index 60e039314..937b16a15 100644 --- a/apps/web/src/components/checkbox/index.js +++ b/apps/web/src/components/checkbox/index.js @@ -1,7 +1,6 @@ import React, { useState, useEffect } from "react"; import { Flex, Text } from "rebass"; import { Switch } from "@rebass/forms"; -import * as Icon from "react-feather"; const CheckBox = props => { const [checked, setChecked] = useState(props.checked || false); diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index 10ba57c91..213eb03f7 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -1,10 +1,7 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; import ReactDOM from "react-dom"; -import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; -import { Input, Checkbox, Label } from "@rebass/forms"; -import * as Icon from "react-feather"; +import { Flex, Box, Text, Button as RebassButton } from "rebass"; import { ThemeProvider } from "../../utils/theme"; -import { db } from "../../common"; import Modal from "react-modal"; export default class Dialog extends React.Component { diff --git a/apps/web/src/components/dialogs/logindialog.js b/apps/web/src/components/dialogs/logindialog.js index 60bd66f24..477ca2c1d 100644 --- a/apps/web/src/components/dialogs/logindialog.js +++ b/apps/web/src/components/dialogs/logindialog.js @@ -1,9 +1,7 @@ -import React, { useState, useEffect } from "react"; -import ReactDOM from "react-dom"; -import { Flex, Box, Text, Button as RebassButton, Button } from "rebass"; -import { Input, Checkbox, Label } from "@rebass/forms"; +import React from "react"; +import { Flex, Box, Button } from "rebass"; +import { Input } from "@rebass/forms"; import * as Icon from "react-feather"; -import { db } from "../../common"; import Dialog, { showDialog } from "./dialog"; const LoginDialog = props => ( diff --git a/apps/web/src/components/listview/index.js b/apps/web/src/components/listview/index.js index 42aaffa84..4fafbf46d 100644 --- a/apps/web/src/components/listview/index.js +++ b/apps/web/src/components/listview/index.js @@ -1,6 +1,5 @@ import React, { useState, useEffect } from "react"; import { Flex, Text } from "rebass"; -import Button from "../button"; import { ev } from "../../common"; import ListItem from "../list-item"; import TimeAgo from "timeago-react"; diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js index e4f190091..269ca6f1a 100644 --- a/apps/web/src/views/Home.js +++ b/apps/web/src/views/Home.js @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import { Flex, Text, Box } from "rebass"; import * as Icon from "react-feather"; import { db, ev, sendNewNoteEvent } from "../common"; -import { GroupedVirtuoso as GroupList, Virtuoso as List } from "react-virtuoso"; +import { GroupedVirtuoso as GroupList } from "react-virtuoso"; import Button from "../components/button"; import Search from "../components/search"; import Note from "../components/note"; diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 3b42d9831..ba69dcb8c 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -1,5 +1,4 @@ import React from "react"; -import * as Icon from "react-feather"; import Note from "../components/note"; import { sendNewNoteEvent } from "../common"; import ListContainer from "../components/list-container"; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index d18a8aa24..56443e35e 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; import { Box, Button, Flex, Text } from "rebass"; import * as Icon from "react-feather"; -import { Switch, Select } from "@rebass/forms"; +import { Switch } from "@rebass/forms"; import "../app.css"; import { changeTheme, isDarkTheme, changeAccent } from "../utils/theme"; From 168e66563bf06f1acbe321cc0252c86b4e85d58a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 22 Feb 2020 14:38:52 +0500 Subject: [PATCH 012/394] fix: use notebook.dateCreated for date --- apps/web/src/components/notebook/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index 84a4aafeb..b007fa23d 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -79,7 +79,7 @@ const Notebook = ({ item, index, onClick, onTopicClick }) => { } info={ - {new Date(notebook.id).toDateString().substring(4)} + {new Date(notebook.dateCreated).toDateString().substring(4)} From 0ed88c475b82109f75dbe69fa227851e3f3e709c Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Sun, 23 Feb 2020 00:15:18 +0500 Subject: [PATCH 013/394] fix: add title for tag when navigating (#15) --- apps/web/src/views/Tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index c22f58310..c81fd827e 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -28,7 +28,7 @@ const Tags = props => { onClick={() => { const notesOfTag = db.notes.tagged(tags[index].title); props.navigator.navigate("notes", { - notes: notesOfTag + notes: notesOfTag,title:tags[index].title }); }} /> From afc6d4cd05cad08d363e7be2f27c115252539e21 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 10:46:20 +0500 Subject: [PATCH 014/394] refactor: separate notebooks store --- apps/web/package.json | 1 + apps/web/src/common/nbstore.js | 31 +++++ apps/web/src/common/store.js | 28 ++--- apps/web/src/components/notebook/index.js | 138 +++++++++++----------- apps/web/src/views/Notebooks.js | 4 +- apps/web/yarn.lock | 7 +- 6 files changed, 120 insertions(+), 89 deletions(-) create mode 100644 apps/web/src/common/nbstore.js diff --git a/apps/web/package.json b/apps/web/package.json index 9f01bc12f..0f278d507 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -6,6 +6,7 @@ "@rebass/forms": "^4.0.6", "emotion-theming": "^10.0.19", "events": "^3.0.0", + "immer": "^5.3.6", "localforage": "^1.7.3", "notes-core": "npm:@streetwriters/notesnook-core@latest", "quill-magic-url": "^1.0.3", diff --git a/apps/web/src/common/nbstore.js b/apps/web/src/common/nbstore.js new file mode 100644 index 000000000..17eb78985 --- /dev/null +++ b/apps/web/src/common/nbstore.js @@ -0,0 +1,31 @@ +import { db } from "./index"; +import createStore from "./store"; + +function notebookStore(set) { + return { + init: function() { + set(state => (state.notebooks = db.notebooks.all)); + }, + notebooks: [], + add: async function(nb) { + let notebook = await db.notebooks.add(nb); + if (notebook) { + set(state => state.notebooks.push(nb)); + } + }, + delete: function() {}, + update: function() {}, + pin: async function(notebook, index) { + await db.notebooks.notebook(notebook).pin(); + set(state => (state.notebooks[index].pinned = !notebook.pinned)); + }, + favorite: async function(notebook, index) { + await db.notebooks.notebook(notebook).favorite(); + set(state => (state.notebooks[index].favorite = !notebook.favorite)); + } + }; +} + +const [useStore, store] = createStore(notebookStore); + +export { useStore, store }; diff --git a/apps/web/src/common/store.js b/apps/web/src/common/store.js index 1c8a4d30e..3f42c3b69 100644 --- a/apps/web/src/common/store.js +++ b/apps/web/src/common/store.js @@ -1,20 +1,14 @@ -import { db } from "./index"; +import produce from "immer"; import create from "zustand"; -const [useStore] = create(set => ({ - init: () => { - console.log("initializing state..."); - set({ - notebooks: db.notebooks.all - }); - }, - notebooks: [], - isSideMenuOpen: false, - addNotebook: async notebook => { - if (await db.notebooks.add(notebook)) { - set({ notebooks: db.notebooks.all }); - } - } -})); +function immer(config) { + return function(set, get, api) { + return config(fn => set(produce(fn)), get, api); + }; +} -export default useStore; +function createStore(store) { + return create(immer(store)); +} + +export default createStore; diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index b007fa23d..9769fa808 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -4,30 +4,17 @@ import * as Icon from "react-feather"; import ListItem from "../list-item"; import { db, ev } from "../../common"; import { showSnack } from "../snackbar"; +import { store } from "../../common/notebook-store"; const dropdownRefs = []; -const menuItems = notebook => [ +const menuItems = (notebook, index) => [ { title: notebook.pinned ? "Unpin" : "Pin", - onClick: async () => - db.notebooks - .notebook(notebook.id) - .pin() - .then(() => { - showSnack("Notebook pinned!", Icon.Check); - ev.emit("refreshNotebooks"); - }) + onClick: () => store.getState().pin(notebook, index) }, { title: notebook.favorite ? "Unfavorite" : "Favorite", - onClick: async () => - db.notebooks - .notebook(notebook.id) - .favorite() - .then(() => { - showSnack("Notebook favorited!", Icon.Check); - ev.emit("refreshNotebooks"); - }) + onClick: () => store.getState().favorite(notebook, index) }, { title: "Edit" }, { title: "Share" }, @@ -45,57 +32,68 @@ const menuItems = notebook => [ } } ]; -const Notebook = ({ item, index, onClick, onTopicClick }) => { - const notebook = item; - return ( - - {notebook.topics.slice(1, 4).map(topic => ( - { - onTopicClick(notebook, topic); - e.stopPropagation(); - }} - key={topic.id + topic.title} - bg="primary" - px={2} - py={1} - sx={{ - marginRight: 1, - borderRadius: "default", - color: "static" - }} - > - - {topic.title} - - - ))} - - } - info={ - - {new Date(notebook.dateCreated).toDateString().substring(4)} - - • - - {notebook.totalNotes} Notes - {notebook.favorite && ( - - )} - - } - pinned={notebook.pinned} - dropdownRefs={dropdownRefs} - index={index} - menuData={notebook} - menuItems={menuItems(notebook)} - /> - ); -}; -export default Notebook; +export default class Notebook extends React.Component { + shouldComponentUpdate(nextProps) { + const prevItem = this.props.item; + const nextItem = nextProps.item; + return ( + prevItem.pinned !== nextItem.pinned || + prevItem.favorite !== nextItem.favorite + ); + } + render() { + const { item, index, onClick, onTopicClick } = this.props; + const notebook = item; + console.log("rendering notebook", notebook.id); + return ( + + {notebook.topics.slice(1, 4).map(topic => ( + { + onTopicClick(notebook, topic); + e.stopPropagation(); + }} + key={topic.id + topic.title} + bg="primary" + px={2} + py={1} + sx={{ + marginRight: 1, + borderRadius: "default", + color: "static" + }} + > + + {topic.title} + + + ))} + + } + info={ + + {new Date(notebook.dateCreated).toDateString().substring(4)} + + • + + {notebook.totalNotes} Notes + {notebook.favorite && ( + + )} + + } + pinned={notebook.pinned} + dropdownRefs={dropdownRefs} + index={index} + menuData={notebook} + menuItems={menuItems(notebook, index)} + /> + ); + } +} diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 7410a1005..8ef630384 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -4,12 +4,14 @@ import { db } from "../common"; import Notebook from "../components/notebook"; import AddNotebookDialog from "../components/dialogs/addnotebookdialog"; import ListContainer from "../components/list-container"; -import useStore from "../common/store"; +import { useStore, store } from "../common/notebook-store"; const Notebooks = props => { const [open, setOpen] = useState(false); + useEffect(() => store.getState().init(), []); const notebooks = useStore(state => state.notebooks); const addNotebook = useStore(state => state.addNotebook); + return ( <> Date: Sun, 23 Feb 2020 10:50:51 +0500 Subject: [PATCH 015/394] feat: create appstore --- apps/web/src/app.js | 6 +----- apps/web/src/components/notebook/index.js | 2 +- apps/web/src/stores/app-store.js | 18 ++++++++++++++++++ .../nbstore.js => stores/notebook-store.js} | 4 ++-- apps/web/src/views/Notebooks.js | 2 +- 5 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/stores/app-store.js rename apps/web/src/{common/nbstore.js => stores/notebook-store.js} (90%) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 374ee0304..4fe202452 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -71,12 +71,8 @@ function App() { 0 ); const [show, setShow] = usePersistentState("navContainerState", true); - const initStore = useStore(state => state.init); - const isSideMenuOpen = useStore(state => state.isSideMenuOpen); - useEffect(() => { - initStore(); - }, [initStore]); + const isSideMenuOpen = useStore(state => state.isSideMenuOpen); useEffect(() => { RootNavigator.navigate(Object.keys(RootNavigator.routes)[selectedIndex]); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index 9769fa808..b61c25892 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -4,7 +4,7 @@ import * as Icon from "react-feather"; import ListItem from "../list-item"; import { db, ev } from "../../common"; import { showSnack } from "../snackbar"; -import { store } from "../../common/notebook-store"; +import { store } from "../../stores/notebook-store"; const dropdownRefs = []; const menuItems = (notebook, index) => [ diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js new file mode 100644 index 000000000..b7e2eec6d --- /dev/null +++ b/apps/web/src/stores/app-store.js @@ -0,0 +1,18 @@ +import { db } from "../common/index"; +import createStore from "../common/store"; + +function appStore(set) { + return { + isSideMenuOpen: false, + closeSideMenu: function() { + set(state => (state.isSideMenuOpen = false)); + }, + openSideMenu: function() { + set(state => (state.isSideMenuOpen = true)); + } + }; +} + +const [useStore, store] = createStore(appStore); + +export { useStore, store }; diff --git a/apps/web/src/common/nbstore.js b/apps/web/src/stores/notebook-store.js similarity index 90% rename from apps/web/src/common/nbstore.js rename to apps/web/src/stores/notebook-store.js index 17eb78985..afb60c8e2 100644 --- a/apps/web/src/common/nbstore.js +++ b/apps/web/src/stores/notebook-store.js @@ -1,5 +1,5 @@ -import { db } from "./index"; -import createStore from "./store"; +import { db } from "../common/index"; +import createStore from "../common/store"; function notebookStore(set) { return { diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 8ef630384..ca6a7844d 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -4,7 +4,7 @@ import { db } from "../common"; import Notebook from "../components/notebook"; import AddNotebookDialog from "../components/dialogs/addnotebookdialog"; import ListContainer from "../components/list-container"; -import { useStore, store } from "../common/notebook-store"; +import { useStore, store } from "../stores/notebook-store"; const Notebooks = props => { const [open, setOpen] = useState(false); From fbd6fb5a116e3b722d4c350d4ff60d0e3741b56e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 10:52:12 +0500 Subject: [PATCH 016/394] fix: make immer happy --- apps/web/src/stores/app-store.js | 1 - apps/web/src/stores/notebook-store.js | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js index b7e2eec6d..4139a219e 100644 --- a/apps/web/src/stores/app-store.js +++ b/apps/web/src/stores/app-store.js @@ -1,4 +1,3 @@ -import { db } from "../common/index"; import createStore from "../common/store"; function appStore(set) { diff --git a/apps/web/src/stores/notebook-store.js b/apps/web/src/stores/notebook-store.js index afb60c8e2..cb4fde242 100644 --- a/apps/web/src/stores/notebook-store.js +++ b/apps/web/src/stores/notebook-store.js @@ -4,7 +4,9 @@ import createStore from "../common/store"; function notebookStore(set) { return { init: function() { - set(state => (state.notebooks = db.notebooks.all)); + set(state => { + state.notebooks = db.notebooks.all; + }); }, notebooks: [], add: async function(nb) { From b3772e1f72207c6d1579541bb9fa0ff2b1b932de Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 10:53:38 +0500 Subject: [PATCH 017/394] fix: rename addNotebook to add --- apps/web/src/views/Notebooks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index ca6a7844d..eb8165043 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -10,7 +10,7 @@ const Notebooks = props => { const [open, setOpen] = useState(false); useEffect(() => store.getState().init(), []); const notebooks = useStore(state => state.notebooks); - const addNotebook = useStore(state => state.addNotebook); + const add = useStore(state => state.add); return ( <> @@ -45,7 +45,7 @@ const Notebooks = props => { /> { setOpen(false); }} From 9f4e3158ee444e8b43275d9a937455345bd01161 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 10:57:21 +0500 Subject: [PATCH 018/394] feat: add delete --- apps/web/src/components/notebook/index.js | 12 +----------- apps/web/src/stores/notebook-store.js | 7 ++++++- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index b61c25892..8cc6052f8 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -2,8 +2,6 @@ import React from "react"; import { Flex, Text } from "rebass"; import * as Icon from "react-feather"; import ListItem from "../list-item"; -import { db, ev } from "../../common"; -import { showSnack } from "../snackbar"; import { store } from "../../stores/notebook-store"; const dropdownRefs = []; @@ -21,15 +19,7 @@ const menuItems = (notebook, index) => [ { title: "Delete", color: "red", - onClick: () => { - db.notebooks.delete(notebook.id).then( - //TODO implement undo - () => { - showSnack("Notebook deleted!", Icon.Check); - ev.emit("refreshNotebooks"); - } - ); - } + onClick: () => store.getState().delete(notebook.id, index) } ]; diff --git a/apps/web/src/stores/notebook-store.js b/apps/web/src/stores/notebook-store.js index cb4fde242..141be3154 100644 --- a/apps/web/src/stores/notebook-store.js +++ b/apps/web/src/stores/notebook-store.js @@ -15,7 +15,12 @@ function notebookStore(set) { set(state => state.notebooks.push(nb)); } }, - delete: function() {}, + delete: async function(id, index) { + await db.notebooks.delete(id); + set(state => { + state.notebooks.splice(index, 1); + }); + }, update: function() {}, pin: async function(notebook, index) { await db.notebooks.notebook(notebook).pin(); From 109da058b21bb2033bcda9b79b53d01517127ca0 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 11:00:53 +0500 Subject: [PATCH 019/394] fix: dropdown not closing on any action on nb --- apps/web/src/components/dropdown/index.js | 3 +++ apps/web/src/components/menu/index.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/apps/web/src/components/dropdown/index.js b/apps/web/src/components/dropdown/index.js index 34f1c8722..50262e8e7 100644 --- a/apps/web/src/components/dropdown/index.js +++ b/apps/web/src/components/dropdown/index.js @@ -10,6 +10,9 @@ import "./styles/Dropdown.css"; var lastOpenedDropdown; class Dropdown extends Component { + static closeLastOpened() { + if (lastOpenedDropdown) lastOpenedDropdown.hide(); + } displayName = "Dropdown"; componentDidMount() { diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index 2b2f3c939..ca08afb04 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -1,5 +1,6 @@ import React from "react"; import { Flex, Box, Text } from "rebass"; +import Dropdown from "../dropdown"; function Menu(props) { return ( @@ -19,6 +20,7 @@ function Menu(props) { key={item.title} onClick={e => { e.stopPropagation(); + Dropdown.closeLastOpened(); if (props.dropdownRef) { props.dropdownRef.hide(); } From 4f81fc78d02368033f326c424e34960a6f09263a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 11:17:05 +0500 Subject: [PATCH 020/394] feat: move openSideMenu to state --- apps/web/src/navigation/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 3e81f4656..cc3e29037 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -3,7 +3,7 @@ import ReactDOM from "react-dom"; import { Box, Flex, Heading, Text } from "rebass"; import * as Icon from "react-feather"; import { ThemeProvider } from "../utils/theme"; -import { ev } from "../common"; +import { useStore } from "../stores/app-store"; export default class Navigator { constructor(root, routes, options = {}) { @@ -75,6 +75,7 @@ export default class Navigator { } const NavigationContainer = props => { + const openSideMenu = useStore(store => store.openSideMenu); return ( @@ -90,7 +91,7 @@ const NavigationContainer = props => { )} ev.emit("openSideMenu")} + onClick={openSideMenu} height={38} color="fontPrimary" sx={{ From 86e0625a739fe19155d9ee35d42614f1c54d99c6 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 23 Feb 2020 11:58:35 +0500 Subject: [PATCH 021/394] feat: make notes logic stateful --- apps/web/src/components/dialogs/confirm.js | 2 +- .../web/src/components/dialogs/logindialog.js | 2 +- .../components/dialogs/move-note-dialog.js | 2 +- apps/web/src/components/note/index.js | 32 +++++-------- apps/web/src/stores/note-store.js | 45 +++++++++++++++++++ apps/web/src/views/Home.js | 29 +++++------- apps/web/yarn.lock | 2 +- 7 files changed, 69 insertions(+), 45 deletions(-) create mode 100644 apps/web/src/stores/note-store.js diff --git a/apps/web/src/components/dialogs/confirm.js b/apps/web/src/components/dialogs/confirm.js index 41c65322e..6a2310217 100644 --- a/apps/web/src/components/dialogs/confirm.js +++ b/apps/web/src/components/dialogs/confirm.js @@ -5,7 +5,7 @@ import Dialog, { showDialog } from "./dialog"; function Confirm(props) { return ( ( [ +const menuItems = (note, index, groupIndex) => [ { title: note.notebook ? "Move" : "Add to", onClick: async () => { @@ -20,25 +21,11 @@ const menuItems = note => [ }, { title: note.pinned ? "Unpin" : "Pin", - onClick: async () => - db.notes - .note(note.id) - .pin() - .then(() => { - showSnack("Note pinned!", Icon.Check); - ev.emit("refreshNotes"); - }) + onClick: () => store.getState().pin(note, index) }, { title: note.favorite ? "Unfavorite" : "Favorite", - onClick: async () => - db.notes - .note(note.id) - .favorite() - .then(() => { - showSnack("Note favorited!", Icon.Check); - ev.emit("refreshNotes"); - }) + onClick: () => store.getState().favorite(note, index) }, { title: "Edit" }, { title: note.locked ? "Remove lock" : "Lock" }, //TODO @@ -51,9 +38,10 @@ const menuItems = note => [ Icon.Trash2, "Delete", "Are you sure you want to delete this note?" - ).then(res => { + ).then(async res => { if (res) { - ev.emit("onClearNote", note.id); + await store.getState().delete(note.id, { index, groupIndex }); + /* ev.emit("onClearNote", note.id); db.notes .delete(note.id) .then( @@ -63,7 +51,7 @@ const menuItems = note => [ ev.emit("refreshNotes"); } ) - .catch(console.log); + .catch(console.log); */ } }); } @@ -74,7 +62,7 @@ function sendOpenNoteEvent(note) { ev.emit("onOpenNote", note); } -const Note = ({ item, index }) => { +const Note = ({ item, index, groupIndex }) => { const note = item; return note ? ( { } pinned={note.pinned} menuData={note} - menuItems={menuItems(note)} + menuItems={menuItems(note, index, groupIndex)} dropdownRefs={dropdownRefs} /> ) : null; diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js new file mode 100644 index 000000000..ac6a10897 --- /dev/null +++ b/apps/web/src/stores/note-store.js @@ -0,0 +1,45 @@ +import { db } from "../common/index"; +import createStore from "../common/store"; + +function noteStore(set) { + return { + init: function() { + set(state => { + //TODO save group type + state.notes = db.notes.group(undefined, true); + }); + }, + notes: { + items: [], + groupCounts: [], + groups: [] + }, + delete: async function(id, info) { + await db.notes.delete(id); + set(state => { + state.notes.items.splice(info.index, 1); + state.notes.groupCounts[info.groupIndex]--; + if (state.notes.groupCounts[info.groupIndex] <= 0) { + state.notes.groups.splice(info.groupIndex, 1); + state.notes.groupCounts.splice(info.groupIndex, 1); + } + }); + }, + pin: async function(note, index) { + await db.notes.note(note).pin(); + set(state => { + state.notes = db.notes.group(undefined, true); + }); + }, + favorite: async function(note, index) { + await db.notes.note(note).favorite(); + set(state => { + state.notes.items[index].favorite = !note.favorite; + }); + } + }; +} + +const [useStore, store] = createStore(noteStore); + +export { useStore, store }; diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js index 269ca6f1a..0be476bcf 100644 --- a/apps/web/src/views/Home.js +++ b/apps/web/src/views/Home.js @@ -1,11 +1,12 @@ import React, { useEffect, useState } from "react"; import { Flex, Text, Box } from "rebass"; import * as Icon from "react-feather"; -import { db, ev, sendNewNoteEvent } from "../common"; +import { db, sendNewNoteEvent } from "../common"; import { GroupedVirtuoso as GroupList } from "react-virtuoso"; import Button from "../components/button"; import Search from "../components/search"; import Note from "../components/note"; +import { useStore, store } from "../stores/note-store"; function SearchBox(props) { return ( @@ -24,25 +25,11 @@ function SearchBox(props) { } function Home() { - const [notes, setNotes] = useState({ - items: [], - groupCounts: [], - groups: [] - }); - useEffect(() => { - function onRefreshNotes() { - let groups = db.notes.group(undefined, true); - setNotes(groups); - } - onRefreshNotes(); - ev.addListener("refreshNotes", onRefreshNotes); - return () => { - ev.removeListener("refreshNotes", onRefreshNotes); - }; - }, []); + useEffect(() => store.getState().init(), []); + const notes = useStore(store => store.notes); return ( - + ( - + )} /> ); }; -var startX, startWidth; - function App() { const [selectedIndex, setSelectedIndex] = usePersistentState( "navSelectedIndex", @@ -72,11 +82,16 @@ function App() { ); const [show, setShow] = usePersistentState("navContainerState", true); - const isSideMenuOpen = useStore(state => state.isSideMenuOpen); + const isSideMenuOpen = useStore(store => store.isSideMenuOpen); + const refreshColors = useStore(store => store.refreshColors); + const setSelectedContext = useNotesStore(store => store.setSelectedContext); useEffect(() => { RootNavigator.navigate(Object.keys(RootNavigator.routes)[selectedIndex]); + refreshColors(); + console.log(colors); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const colors = useStore(store => store.colors); return ( - - {Object.values(RootNavigator.routes).map( - (item, index) => - !item.bottom && ( - { - if (item.onClick) { - return item.onClick(); - } - if (selectedIndex === index) { - setShow(!show); - return; - } - if (RootNavigator.navigate(item.key)) { - setSelectedIndex(index); - } - }} - key={item.key} - item={item} - selected={selectedIndex === index} - /> - ) - )} + + {Object.values(routes).map((item, index) => ( + { + if (selectedIndex === index) { + setShow(!show); + return; + } + if (RootNavigator.navigate(item.key)) { + setSelectedIndex(index); + } + }} + key={item.key} + item={item} + selected={selectedIndex === index} + /> + ))} + {colors.map(color => { + return ( + { + setSelectedContext({ type: "color", value: color.title }); + RootNavigator.navigate("color", { + title: toTitleCase(color.title), + context: { colors: [color.title] } + }); + }} + key={color.title} + item={{ + color: COLORS[color.title], + title: toTitleCase(color.title), + icon: Icon.Circle, + count: color.count + }} + /> + ); + })} - {Object.values(RootNavigator.routes).map( - (item, index) => - item.bottom && ( - { - if (item.onClick) { - return item.onClick(); - } - if (selectedIndex === index) { - setShow(!show); - return; - } - if (RootNavigator.navigate(item.key)) { - setSelectedIndex(index); - } - }} - key={item.key} - item={item} - selected={selectedIndex === index} - /> - ) - )} + {Object.values(bottomRoutes).map((item, index) => ( + { + if (item.onClick) { + return item.onClick(); + } + if (RootNavigator.navigate(item.key)) { + setSelectedIndex(index); + } + }} + key={item.key} + item={item} + selected={selectedIndex === index} + /> + ))} @@ -170,36 +195,6 @@ function App() { flex="1 1 auto" //style={{ width: "362px" }} /> - { - startX = e.clientX; - let view = document - .querySelector(".RootNavigator") - .getBoundingClientRect(); - startWidth = parseInt(view.width, 10); - }} - onDrag={e => { - let view = document.querySelector(".RootNavigator"); - view.style.width = `${startWidth + e.clientX - startX}px`; - }} - onDragEnd={() => { - let view = document.querySelector(".RootNavigator"); - view.style.width = view.getBoundingClientRect().width; - window.localStorage.setItem( - "navigationViewWidth", - view.style.width - ); - }} - /> diff --git a/apps/web/src/common/index.js b/apps/web/src/common/index.js index a22df31ee..b99e76daa 100644 --- a/apps/web/src/common/index.js +++ b/apps/web/src/common/index.js @@ -5,14 +5,14 @@ import events from "events"; export const db = new Database(StorageInterface); export const ev = new events.EventEmitter(); -export const COLORS = [ - { label: "red", code: "#ed2d37" }, - { label: "orange", code: "#ec6e05" }, - { label: "yellow", code: "yellow" }, - { label: "green", code: "green" }, - { label: "blue", code: "blue" }, - { label: "purple", code: "purple" }, - { label: "gray", code: "gray" } -]; +export const COLORS = { + red: "#ed2d37", + orange: "#ec6e05", + yellow: "yellow", + green: "green", + blue: "blue", + purple: "purple", + gray: "gray" +}; export const DEFAULT_CONTEXT = { colors: [], tags: [], notebook: {} }; diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 0f8651a2c..56c121fad 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -7,6 +7,7 @@ import { PinIcon } from "../icons"; import { usePersistentState } from "../../utils/hooks"; import { useStore } from "../../stores/editor-store"; import { COLORS } from "../../common"; +import { objectMap } from "../../utils/object"; const Properties = props => { const [visible, setVisible] = usePersistentState("propertiesVisible", false); @@ -141,21 +142,21 @@ const Properties = props => { Colors: - {COLORS.map(color => ( + {objectMap(COLORS, (label, code) => ( setColor(color.label)} - key={color.label} + onClick={() => setColor(label)} + key={label} > - {colors.includes(color.label) && ( + {colors.includes(label) && ( { - onClickMethod("Red", "red"); - } - }), - ...createColorRoute("Orange", Notes, "#ec6e05", { - onClick: () => { - onClickMethod("Orange", "orange"); - } - }), - ...createColorRoute("Yellow", Notes, "yellow", { - onClick: () => { - onClickMethod("Yellow", "yellow"); - } - }), - ...createColorRoute("Green", Notes, "green", { - onClick: () => { - onClickMethod("Green", "green"); - } - }), - ...createColorRoute("Blue", Notes, "blue", { - onClick: () => { - onClickMethod("Blue", "blue"); - } - }), - ...createColorRoute("Purple", Notes, "purple", { - onClick: () => { - onClickMethod("Purple", "purple"); - } - }), - ...createColorRoute("Gray", Notes, "gray", { - onClick: () => { - onClickMethod("Gray", "gray"); - } - }) -}; - -function onClickMethod(Title, label) { - RootNavigator.navigate(Title, { - notes: db.notes.colored(label), - context: { colors: [label] } - }); -} - -const bottomRoutes = { +export const bottomRoutes = { ...createDeadRoute("nightmode", Icon.Moon, { onClick: () => changeTheme(), bottom: true, @@ -81,19 +29,25 @@ const bottomRoutes = { }) }; -const routes = { +export const routes = { ...createNormalRoute("home", Home, Icon.Home), ...createRoute("notebooks", NotebooksContainer, { icon: Icon.Book }), ...createNormalRoute("favorites", Favorites, Icon.Star), ...createNormalRoute("trash", Trash, Icon.Trash2), - ...createRoute("tags", TagsContainer, { icon: Icon.Tag }), - ...colorRoutes, - ...bottomRoutes + ...createRoute("tags", TagsContainer, { icon: Icon.Tag }) }; -const RootNavigator = new Navigator("RootNavigator", routes, { - backButtonEnabled: false -}); +const invisibleRoutes = { + ...createNormalRoute("color", Notes, Icon.Circle) +}; + +const RootNavigator = new Navigator( + "RootNavigator", + { ...routes, ...invisibleRoutes }, + { + backButtonEnabled: false + } +); export default RootNavigator; diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js index 4139a219e..571fa26c2 100644 --- a/apps/web/src/stores/app-store.js +++ b/apps/web/src/stores/app-store.js @@ -1,4 +1,5 @@ import createStore from "../common/store"; +import { db } from "../common"; function appStore(set) { return { @@ -8,6 +9,12 @@ function appStore(set) { }, openSideMenu: function() { set(state => (state.isSideMenuOpen = true)); + }, + colors: [], + refreshColors: function() { + set(state => { + state.colors = db.colors.all; + }); } }; } diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index b1fd12655..7b4e2c66c 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -1,5 +1,6 @@ import createStore from "../common/store"; import { store as notestore, LIST_TYPES } from "./note-store"; +import { store as appStore } from "./app-store"; import { db } from "../common"; const SESSION_STATES = { @@ -61,7 +62,10 @@ function editorStore(set, get) { }; db.notes.add(note).then(id => { if (tags.length > 0) updateContext("tags", tags); - if (colors.length > 0) updateContext("colors", colors); + if (colors.length > 0) { + updateContext("colors", colors); + appStore.getState().refreshColors(); + } set(state => { state.session.id = id; @@ -96,7 +100,7 @@ function editorStore(set, get) { }); }, setColor: function(color) { - setTagOrColor(get().session, "colors", color, "color", set); + setTagOrColor(get().session, "colors", color, "color", get().setSession); }, setTag: function(tag) { setTagOrColor(get().session, "tags", tag, "tag", get().setSession); @@ -105,6 +109,7 @@ function editorStore(set, get) { } function setTagOrColor(session, array, value, func, set) { + console.log(arguments); const { [array]: arr, id } = session; let note = db.notes.note(id); if (!note) return; @@ -132,7 +137,6 @@ function updateContext(key, array) { if (context.type === type) { array.forEach(value => { if (context.value === value) { - console.log("updating according to context"); notestore.getState().setSelectedContext(context); } }); diff --git a/apps/web/src/utils/object.js b/apps/web/src/utils/object.js new file mode 100644 index 000000000..10d9b5ceb --- /dev/null +++ b/apps/web/src/utils/object.js @@ -0,0 +1,3 @@ +export function objectMap(obj, fn) { + return Object.entries(obj).map(([k, v], i) => fn(k, v, i)); +} diff --git a/apps/web/src/utils/string.js b/apps/web/src/utils/string.js new file mode 100644 index 000000000..9953d7717 --- /dev/null +++ b/apps/web/src/utils/string.js @@ -0,0 +1,3 @@ +export function toTitleCase(str) { + return str[0].toUpperCase() + str.substring(1); +} diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index fe3dafbce..15c13441c 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -6813,7 +6813,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@https://github.com/thecodrr/notes-core.git": version "1.1.0" - resolved "https://github.com/thecodrr/notes-core.git#fafece9f7d74a4bbc64de9c6083444c56a636d45" + resolved "https://github.com/thecodrr/notes-core.git#418e48b357179db10ddb6b3116b61c5746c92e48" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From be0c9d6498f601718351f42e4051b37cb812863e Mon Sep 17 00:00:00 2001 From: alihamuh Date: Wed, 26 Feb 2020 04:56:32 -0500 Subject: [PATCH 046/394] to do list. From ed602e983bf7b65dc9188114d3f36773775e6bb7 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 26 Feb 2020 15:00:24 +0500 Subject: [PATCH 047/394] fix: navigating to color routes does not unselect the previously selected route --- apps/web/src/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 420173582..e268bacd6 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -145,6 +145,7 @@ function App() { return ( { + setSelectedIndex(-1); setSelectedContext({ type: "color", value: color.title }); RootNavigator.navigate("color", { title: toTitleCase(color.title), From c0380175d9edc9f33a9a022c5b923bffd953dfcd Mon Sep 17 00:00:00 2001 From: alihamuh Date: Wed, 26 Feb 2020 05:01:31 -0500 Subject: [PATCH 048/394] to do list From 52a58a627cdbf1e4aa71199bb550db682c58dfd2 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 26 Feb 2020 15:06:24 +0500 Subject: [PATCH 049/394] chore: update readme.md --- apps/web/README.md | 69 ++-------------------------------------------- 1 file changed, 2 insertions(+), 67 deletions(-) diff --git a/apps/web/README.md b/apps/web/README.md index 89b278ae3..fa4ff36c3 100644 --- a/apps/web/README.md +++ b/apps/web/README.md @@ -1,68 +1,3 @@ -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +

Notesnook

-## Available Scripts - -In the project directory, you can run: - -### `yarn start` - -Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser. - -The page will reload if you make edits.
-You will also see any lint errors in the console. - -### `yarn test` - -Launches the test runner in the interactive watch mode.
-See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `yarn build` - -Builds the app for production to the `build` folder.
-It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.
-Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `yarn eject` - -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** - -If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. - -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting - -### Analyzing the Bundle Size - -This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size - -### Making a Progressive Web App - -This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app - -### Advanced Configuration - -This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration - -### Deployment - -This section has moved here: https://facebook.github.io/create-react-app/docs/deployment - -### `yarn build` fails to minify - -This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify +The best notes app in the world. From 8185cb24d83e5c56f505c8c0413a5c4195ece151 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 26 Feb 2020 21:47:11 +0500 Subject: [PATCH 050/394] ui: minor optimizations --- apps/web/src/app.js | 8 +-- apps/web/src/components/editor/titlebox.js | 4 +- apps/web/src/navigation/index.js | 50 +++++++++++-------- .../navigation/navigators/rootnavigator.js | 8 +-- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index e268bacd6..515ab46d8 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -37,9 +37,10 @@ const NavMenuItem = props => { borderRadius: "none", textAlign: "center", color: props.selected ? "primary" : props.item.color || "text", - transition: "color 100ms linear", + transition: "color 100ms, background-color 100ms linear", ":hover": { - color: "primary" + color: "primary", + backgroundColor: "shade" } }} px={0} @@ -112,7 +113,7 @@ function App() { display: [isSideMenuOpen ? "flex" : "none", "flex", "flex"], position: ["absolute", "relative", "relative"] }} - bg={"shade"} + bg={"background"} px={0} > ))} diff --git a/apps/web/src/components/editor/titlebox.js b/apps/web/src/components/editor/titlebox.js index ded24a83d..919af5dfe 100644 --- a/apps/web/src/components/editor/titlebox.js +++ b/apps/web/src/components/editor/titlebox.js @@ -27,8 +27,8 @@ export default class TitleBox extends React.Component { sx={{ borderWidth: 0, ":focus": { outline: "none" }, - paddingTop: 0, - paddingBottom: 0 + paddingTop: 1, + paddingBottom: 1 }} px={2} value={title} diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index fe6490237..363eb89d6 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -76,36 +76,42 @@ export default class Navigator { const NavigationContainer = props => { const openSideMenu = useStore(store => store.openSideMenu); + console.log(props); return ( - - {props.canGoBack && ( + {(props.route.title || props.route.params.title) && ( + + {props.canGoBack && ( + + + + )} - + - )} - - - - - {props.route.title || props.route.params.title} - - + + {props.route.title || props.route.params.title} + + + )} {props.route.params.subtitle} diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index c56974cfd..5b8b07257 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -30,12 +30,14 @@ export const bottomRoutes = { }; export const routes = { - ...createNormalRoute("home", Home, Icon.Home), + ...createNormalRoute("home", Home, Icon.Home, { title: "Home" }), ...createRoute("notebooks", NotebooksContainer, { icon: Icon.Book }), - ...createNormalRoute("favorites", Favorites, Icon.Star), - ...createNormalRoute("trash", Trash, Icon.Trash2), + ...createNormalRoute("favorites", Favorites, Icon.Star, { + title: "Favorites" + }), + ...createNormalRoute("trash", Trash, Icon.Trash, { title: "Trash" }), ...createRoute("tags", TagsContainer, { icon: Icon.Tag }) }; From 6e0f28fb8121ff40466fc83c38306ee7721e0f8f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 26 Feb 2020 21:54:44 +0500 Subject: [PATCH 051/394] ui: reduce fav & lock icon size in note --- apps/web/src/components/note/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index dfbc95a05..b048c31ec 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -73,8 +73,8 @@ export default class Note extends React.Component { info={ - {note.locked && } - {note.favorite && } + {note.locked && } + {note.favorite && } } pinned={note.pinned} From d6a7d2f2049431e98425d9502131d2d0f3f1f025 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 26 Feb 2020 22:12:11 +0500 Subject: [PATCH 052/394] feat: add opened note indicator --- .../src/components/list-container/index.js | 26 ++- apps/web/src/components/list-item/index.js | 211 +++++++++--------- apps/web/src/components/note/index.js | 1 + apps/web/src/stores/editor-store.js | 17 +- apps/web/src/stores/note-store.js | 6 + 5 files changed, 142 insertions(+), 119 deletions(-) diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 81b4d0cd6..9dc1e0264 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -9,16 +9,24 @@ const ListContainer = props => { return ( - + > + + {props.button && ( - + - - -
- } - /> -); +const LoginDialog = props => { + const [username, setUsername] = useState(); + const [password, setPassword] = useState(); + const [errorMessage, setErrorMessage] = useState(); + + return ( + { + setErrorMessage(); + if (username === "" || username === undefined) { + setErrorMessage("Please enter your username."); + return; + } + + if (password === "" || password === undefined) { + setErrorMessage("Please enter your password."); + return; + } + + db.user.login(username, password); + } + }} + content={ + + { + setUsername(e.target.value); + }} + > + { + setPassword(e.target.value); + }} + > + + + + + + {errorMessage} + + + + } + /> + ); +}; export const showLogInDialog = () => { return showDialog(perform => perform(false)} />); diff --git a/apps/web/src/components/dialogs/signupdialog.js b/apps/web/src/components/dialogs/signupdialog.js new file mode 100644 index 000000000..1c4de0ee2 --- /dev/null +++ b/apps/web/src/components/dialogs/signupdialog.js @@ -0,0 +1,104 @@ +import React, { useState } from "react"; +import { Flex, Box, Text } from "rebass"; +import { Input } from "@rebass/forms"; +import * as Icon from "react-feather"; +import Dialog, { showDialog } from "./dialog"; +import { db } from "../../common"; + +const SignUpDialog = props => { + const [username, setUserName] = useState(); + const [email, setEmail] = useState(); + const [password, setPassword] = useState(); + const [confirmPassword, setConfirmPassword] = useState(); + const [errorMessage, setErrorMessage] = useState(); + return ( + { + setErrorMessage(); + + if (username === "" || username === undefined) { + setErrorMessage("Please enter your username."); + return; + } + + if (email === "" || email === undefined) { + setErrorMessage("Please enter your email address."); + return; + } + + if (password !== confirmPassword) { + setErrorMessage("Passwords do not match! Please try again."); + return; + } + + if (password === undefined || password === "") { + setErrorMessage("Please enter password."); + return; + } + + db.user.signup(username, email, password); + } + }} + content={ + + { + setUserName(e.target.value); + }} + > + { + setEmail(e.target.value); + }} + > + { + setPassword(e.target.value); + }} + > + { + setConfirmPassword(e.target.value); + }} + > + + + {errorMessage} + + + + } + /> + ); +}; + +export const showSignUpDialog = () => { + return showDialog(perform => perform(false)} />); +}; From 057631ae4cac86ab7fa7e768a98de26309363dd9 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 11 Mar 2020 12:19:29 +0500 Subject: [PATCH 216/394] fix: favorites nav item not selecting --- apps/web/src/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 4b0541756..69098dddf 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -142,6 +142,7 @@ function App() { return; } if (item.onClick) { + setSelectedKey(item.key); return item.onClick(); } if (RootNavigator.navigate(item.key)) { From e1db2f0663f019295ee91496529209fd71ec3448 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 11 Mar 2020 12:23:01 +0500 Subject: [PATCH 217/394] fix: subnavigator not opening --- apps/web/src/views/Notebooks.js | 6 +++--- apps/web/src/views/Tags.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 675d2b29d..3a7826e66 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -61,14 +61,14 @@ const Notebooks = props => { ); }; -const NotebooksContainer = props => { +const NotebooksContainer = () => { useEffect(() => { const NotebookNavigator = require("../navigation/navigators/nbnavigator") .default; - if (!NotebookNavigator.restore(props)) { + if (!NotebookNavigator.restore()) { NotebookNavigator.navigate("notebooks"); } - }, [props]); + }, []); return ( { ); }; -const TagsContainer = props => { +const TagsContainer = () => { useEffect(() => { const TagNavigator = require("../navigation/navigators/tagnavigator") .default; - if (!TagNavigator.restore(props)) { + if (!TagNavigator.restore()) { TagNavigator.navigate("tags"); } - }, [props]); + }, []); return ( ); From 6e4af154efeb44926f4af51dd8639b3c575810e4 Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Wed, 11 Mar 2020 12:29:50 +0500 Subject: [PATCH 218/394] fix: navigator view not hiding in focus mode (#127) * root navigator * root-nav-changes * dependency removed * z-index val --- apps/web/src/app.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 69098dddf..dc078f4fa 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -97,8 +97,12 @@ function App() { }, []); useEffect(() => { - if (isFocusModeEnabled) setShow(false); - }, [isFocusModeEnabled, setShow, show]); + if (isFocusModeEnabled) { + setShow(false); + } else { + setShow(true); + } + }, [isFocusModeEnabled]); const colors = useStore(store => store.colors); return ( @@ -206,10 +210,10 @@ function App() { Date: Wed, 11 Mar 2020 12:33:06 +0500 Subject: [PATCH 219/394] chore: ignore eslint warning --- apps/web/src/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index dc078f4fa..2dcb66ef3 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -102,7 +102,9 @@ function App() { } else { setShow(true); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isFocusModeEnabled]); + const colors = useStore(store => store.colors); return ( From d7194b0ddd6e29d305156193b2e97e5d8a2ad5a1 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 11 Mar 2020 12:40:00 +0500 Subject: [PATCH 220/394] ui: animate when entering focus mode --- apps/web/src/app.js | 174 ++++++++++++------------ apps/web/src/components/editor/index.js | 15 +- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 2dcb66ef3..339f4b9a0 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -17,6 +17,7 @@ import { COLORS } from "./common"; import { toTitleCase } from "./utils/string"; import * as Icon from "react-feather"; import { useStore as useAppStore } from "./stores/app-store"; +import Animated from "./components/animated"; const NavMenuItem = props => { const [fill, setFill] = useState(); @@ -114,100 +115,101 @@ function App() { height="100%" alignContent="stretch" > - {!isFocusModeEnabled && ( - + - - {Object.values(routes).map((item, index) => ( + {Object.values(routes).map((item, index) => ( + { + if (selectedKey === item.key) { + setShow(!show); + return; + } + if (item.onClick) { + setSelectedKey(item.key); + return item.onClick(); + } + if (RootNavigator.navigate(item.key)) { + setSelectedKey(item.key); + } + }} + key={item.key} + item={item} + selected={selectedKey === item.key} + /> + ))} + {colors.map(color => { + return ( { - if (selectedKey === item.key) { - setShow(!show); - return; - } - if (item.onClick) { - setSelectedKey(item.key); - return item.onClick(); - } - if (RootNavigator.navigate(item.key)) { - setSelectedKey(item.key); - } + setSelectedKey(undefined); + setSelectedContext({ + type: "color", + value: color.title + }); + RootNavigator.navigate( + "color", + { + title: toTitleCase(color.title), + context: { colors: [color.title] } + }, + true + ); }} - key={item.key} - item={item} - selected={selectedKey === item.key} - /> - ))} - {colors.map(color => { - return ( - { - setSelectedKey(undefined); - setSelectedContext({ - type: "color", - value: color.title - }); - RootNavigator.navigate( - "color", - { - title: toTitleCase(color.title), - context: { colors: [color.title] } - }, - true - ); - }} - key={color.title} - item={{ - color: COLORS[color.title], - title: toTitleCase(color.title), - icon: Icon.Circle, - count: color.count - }} - /> - ); - })} - - - {Object.values(bottomRoutes).map((item, index) => ( - { - if (item.onClick) { - return item.onClick(); - } - if (RootNavigator.navigate(item.key)) { - setSelectedKey(item.key); - } + key={color.title} + item={{ + color: COLORS[color.title], + title: toTitleCase(color.title), + icon: Icon.Circle, + count: color.count }} - key={item.key} - item={item} - selected={selectedKey === item.key} /> - ))} - - - )} + ); + })} + + + {Object.values(bottomRoutes).map((item, index) => ( + { + if (item.onClick) { + return item.onClick(); + } + if (RootNavigator.navigate(item.key)) { + setSelectedKey(item.key); + } + }} + key={item.key} + item={item} + selected={selectedKey === item.key} + /> + ))} + + { const theme = useTheme(); @@ -48,12 +49,16 @@ function Editor() { }, [reopenLastSession]); return ( - {id && } - + ); } From 4b84e363f4390405611e486e7098f660e958bda4 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 11 Mar 2020 14:56:30 +0500 Subject: [PATCH 221/394] ui: more vibrant gold color for favorite star --- apps/web/src/components/note/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index c58a3ad14..910d20677 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -104,7 +104,7 @@ function Note(props) { {note.favorite && ( From 4bc4de43295e52c7d7bb9fe2db4e440204138130 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 09:25:12 +0500 Subject: [PATCH 222/394] fix: #107 --- apps/web/src/stores/editor-store.js | 5 ++++- apps/web/src/stores/tag-store.js | 18 ++++++++++++++++++ apps/web/src/views/Tags.js | 10 +++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/stores/tag-store.js diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index dc15d072a..da481ed7a 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -1,6 +1,7 @@ import createStore from "../common/store"; import { store as noteStore, LIST_TYPES } from "./note-store"; import { store as appStore } from "./app-store"; +import { store as tagStore } from "./tag-store"; import { db } from "../common"; import { showPasswordDialog } from "../components/dialogs/passworddialog"; @@ -205,11 +206,13 @@ function updateContext(key, array) { // update notes if the selected context (the current view in the navigator) is a tag or color const notesState = noteStore.getState(); const context = notesState.selectedContext; - console.log(context); if (context.type === type) { const isValue = array.some(value => value === context.value); if (isValue) noteStore.getState().setSelectedContext(context); } + if (type === "tag") { + tagStore.getState().refreshTags(); + } } const [useStore, store] = createStore(editorStore); diff --git a/apps/web/src/stores/tag-store.js b/apps/web/src/stores/tag-store.js new file mode 100644 index 000000000..7d8ff986d --- /dev/null +++ b/apps/web/src/stores/tag-store.js @@ -0,0 +1,18 @@ +import createStore from "../common/store"; +import { db } from "../common"; +import { showPasswordDialog } from "../components/dialogs/passworddialog"; + +function tagStore(set, get) { + return { + tags: [], + refreshTags: function() { + set(state => { + state.tags = db.tags.all; + }); + } + }; +} + +const [useStore, store] = createStore(tagStore); + +export { useStore, store }; diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index 6f70cd418..b7dd8cba6 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -3,7 +3,8 @@ import { Flex, Text } from "rebass"; import ListContainer from "../components/list-container"; import ListItem from "../components/list-item"; import { db } from "../common"; -import { useStore } from "../stores/note-store"; +import { useStore as useNotesStore } from "../stores/note-store"; +import { useStore, store } from "../stores/tag-store"; import TagsPlaceholder from "../components/placeholders/tags-placeholder"; const TagNode = ({ title }) => ( @@ -16,8 +17,11 @@ const TagNode = ({ title }) => ( ); const Tags = props => { - const setSelectedContext = useStore(store => store.setSelectedContext); - const tags = db.tags.all; + const setSelectedContext = useNotesStore(store => store.setSelectedContext); + const tags = useStore(store => store.tags); + useEffect(() => { + store.getState().refreshTags(); + }, []); return ( Date: Sat, 14 Mar 2020 09:29:31 +0500 Subject: [PATCH 223/394] fix: #74 --- apps/web/src/common/selectionoptions.js | 5 +++++ apps/web/src/stores/tag-store.js | 1 - apps/web/src/views/Tags.js | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 7dd9590ac..196c506b9 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -5,6 +5,7 @@ import { store as nbStore } from "../stores/notebook-store"; import { store as editorStore } from "../stores/editor-store"; import { db } from "./index"; import { showMoveNoteDialog } from "../components/dialogs/movenotedialog"; +import { confirm } from "../components/dialogs/confirm"; function createOption(icon, onClick) { return { @@ -21,6 +22,10 @@ function createOptions(options = []) { } const DeleteOption = createOption(Icon.Trash2, async function(state) { + if ( + !(await confirm(Icon.Trash2, "Delete", "Are you sure you want to proceed?")) + ) + return; const item = state.selectedItems[0]; var isAnyNoteOpened = false; const editorState = editorStore.getState(); diff --git a/apps/web/src/stores/tag-store.js b/apps/web/src/stores/tag-store.js index 7d8ff986d..abce60bbf 100644 --- a/apps/web/src/stores/tag-store.js +++ b/apps/web/src/stores/tag-store.js @@ -1,6 +1,5 @@ import createStore from "../common/store"; import { db } from "../common"; -import { showPasswordDialog } from "../components/dialogs/passworddialog"; function tagStore(set, get) { return { diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index b7dd8cba6..57014c011 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -2,7 +2,6 @@ import React, { useEffect } from "react"; import { Flex, Text } from "rebass"; import ListContainer from "../components/list-container"; import ListItem from "../components/list-item"; -import { db } from "../common"; import { useStore as useNotesStore } from "../stores/note-store"; import { useStore, store } from "../stores/tag-store"; import TagsPlaceholder from "../components/placeholders/tags-placeholder"; From 871878b3f778eb0ceafe974b673edcd2fbb4657f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 09:31:51 +0500 Subject: [PATCH 224/394] fix: #75 --- apps/web/src/common/selectionoptions.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 196c506b9..31b5d3ec6 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -77,10 +77,15 @@ const AddToNotebookOption = createOption(Icon.Plus, async function(state) { } }); +const RestoreOption = createOption(Icon.RefreshCcw, async function(state) { + const items = state.selectedItems.map(item => item.id); + await db.trash.restore(items); +}); + const NotesOptions = createOptions([AddToNotebookOption, FavoriteOption]); const NotebooksOptions = createOptions(); const TopicOptions = createOptions(); -const TrashOptions = createOptions(); +const TrashOptions = createOptions([RestoreOption]); const FavoritesOptions = createOptions([UnfavoriteOption]); export default { From e74f12e266e10e6fce36b4d56acedb877fd87f08 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 09:36:47 +0500 Subject: [PATCH 225/394] fix: #105 --- apps/web/src/common/selectionoptions.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 31b5d3ec6..7466cd07b 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -6,6 +6,7 @@ import { store as editorStore } from "../stores/editor-store"; import { db } from "./index"; import { showMoveNoteDialog } from "../components/dialogs/movenotedialog"; import { confirm } from "../components/dialogs/confirm"; +import { showPasswordDialog } from "../components/dialogs/passworddialog"; function createOption(icon, onClick) { return { @@ -29,8 +30,24 @@ const DeleteOption = createOption(Icon.Trash2, async function(state) { const item = state.selectedItems[0]; var isAnyNoteOpened = false; const editorState = editorStore.getState(); - const items = state.selectedItems.map(item => { + const items = state.selectedItems.map(async item => { if (item.id === editorState.session.id) isAnyNoteOpened = true; + if (item.locked) { + if ( + !(await confirm( + Icon.Trash2, + "Delete", + "This is a locked note. Are you sure you want to delete it?" + )) || + !(await showPasswordDialog("unlock_note", password => { + return db.vault + .unlock(password) + .then(() => true) + .catch(() => false); + })) + ) + return 0; + } return item.id; }); From 8d72daa82c4ebc7fe1d7ad8f6e0ce7569185d6bc Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 09:48:41 +0500 Subject: [PATCH 226/394] fix: #128 --- apps/web/src/components/list-item/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index b3e7ef2f4..5c5b6dbed 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -71,12 +71,12 @@ const ListItem = props => { ); useEffect(() => { - if (!isSelectionMode) setIsSelected(false); - }, [isSelectionMode]); + if (!isSelectionMode && isSelected) toggleSelection(); + }, [isSelectionMode, toggleSelection, isSelected]); useEffect(() => { - if (shouldSelectAll) setIsSelected(true); - }, [shouldSelectAll]); + if (shouldSelectAll && !isSelected) toggleSelection(); + }, [shouldSelectAll, toggleSelection, isSelected]); useEffect(() => { if (props.selectable) { From b9ab13720a8a509a87c8eb36d78bd81b075a5d23 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 09:52:21 +0500 Subject: [PATCH 227/394] fix: #129 --- apps/web/src/components/dialogs/add-notebook-dialog.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index d06aac113..5b3197c89 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -69,6 +69,8 @@ export default class AddNotebookDialog extends React.Component { this.description = ""; this._inputRefs = []; this.lastLength = 0; + this.topics = []; + this.id = undefined; this.setState({ topics: [""], focusedInputIndex: 0 From 351f8a3f421e3243bb541457950760c9606c71f8 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 10:41:15 +0500 Subject: [PATCH 228/394] fix: #130 --- apps/web/src/common/selectionoptions.js | 2 +- apps/web/src/components/list-container/index.js | 8 ++++++++ apps/web/src/components/list-item/index.js | 14 ++++++-------- apps/web/src/stores/app-store.js | 8 +++++++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 7466cd07b..b82d610cb 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -83,7 +83,7 @@ const UnfavoriteOption = createOption(Icon.Star, function(state) { if (!item.favorite) return; await db.notes.note(item.id).favorite(); }); - notesStore.getState().refreshList(LIST_TYPES.fav); + notesStore.getState().setSelectedContext({ type: "favorites" }); }); const AddToNotebookOption = createOption(Icon.Plus, async function(state) { diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 566b4b8cc..9ee87f551 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -5,8 +5,16 @@ import Search from "../search"; import * as Icon from "react-feather"; import { Virtuoso as List } from "react-virtuoso"; import { useStore as useSearchStore } from "../../stores/searchstore"; +import { useStore as useAppStore } from "../../stores/app-store"; + const ListContainer = props => { const setSearchContext = useSearchStore(store => store.setSearchContext); + const shouldSelectAll = useAppStore(store => store.shouldSelectAll); + const setSelectedItems = useAppStore(store => store.setSelectedItems); + useEffect(() => { + if (shouldSelectAll) setSelectedItems(props.items); + }, [shouldSelectAll, setSelectedItems, props.items]); + useEffect(() => { if (props.noSearch) return; setSearchContext({ diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 5c5b6dbed..9371e82dc 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -9,6 +9,7 @@ import { } from "../../stores/app-store"; import useContextMenu from "../../utils/useContextMenu"; import { useTheme } from "emotion-theming"; +import { isShorthandPropertyAssignment } from "typescript"; const ActionsMenu = props => ( { `contextMenu${props.index}` ); const isSelectionMode = useAppStore(store => store.isSelectionMode); - const shouldSelectAll = useAppStore(store => store.shouldSelectAll); + const selectedItems = useAppStore(store => store.selectedItems); + const isSelected = + selectedItems.findIndex(item => props.item.id === item.id) > -1; const selectItem = useAppStore(store => store.selectItem); - const [isSelected, setIsSelected] = useState(false); const [menuItems, setMenuItems] = useState(props.menuItems); const theme = useTheme(); + const toggleSelection = useCallback( function toggleSelection() { - setIsSelected(state => !state); selectItem(props.item); }, - [setIsSelected, selectItem, props.item] + [selectItem, props.item] ); useEffect(() => { if (!isSelectionMode && isSelected) toggleSelection(); }, [isSelectionMode, toggleSelection, isSelected]); - useEffect(() => { - if (shouldSelectAll && !isSelected) toggleSelection(); - }, [shouldSelectAll, toggleSelection, isSelected]); - useEffect(() => { if (props.selectable) { setMenuItems([ diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js index 3bc477926..0999582df 100644 --- a/apps/web/src/stores/app-store.js +++ b/apps/web/src/stores/app-store.js @@ -50,11 +50,13 @@ function appStore(set, get) { enterSelectionMode: function() { set(state => { state.isSelectionMode = true; + state.shouldSelectAll = false; }); }, exitSelectionMode: function() { set(state => { state.isSelectionMode = false; + state.shouldSelectAll = false; state.selectedItems = []; }); }, @@ -66,12 +68,16 @@ function appStore(set, get) { } else { state.selectedItems.push(item); } - state.shouldSelectAll = false; }); if (get().selectedItems.length <= 0) { get().exitSelectionMode(); } }, + setSelectedItems: function(items) { + set(state => { + state.selectedItems = items; + }); + }, selectAll() { if (!get().isSelectionMode) return; set(state => { From 3bb8334793957e7238ced5fb914819d9bb7ebb54 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 10:46:17 +0500 Subject: [PATCH 229/394] fix: #131 --- apps/web/src/navigation/index.js | 130 +++++++++--------- .../src/navigation/navigators/nbnavigator.js | 5 +- .../navigation/navigators/rootnavigator.js | 6 +- 3 files changed, 74 insertions(+), 67 deletions(-) diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index a2b56d043..2e1052569 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -92,79 +92,85 @@ const NavigationContainer = props => { {(props.route.title || props.route.params.title) && ( - - - {props.canGoBack && ( + <> + + + {props.canGoBack && ( + + + + )} - + + + {props.route.title || props.route.params.title} + + + {props.route.options && isSelectionMode && ( + + {props.route.options.map(option => ( + + + + ))} + )} - + {props.route.params.subtitle && ( + - - - - {props.route.title || props.route.params.title} - - - {props.route.options && isSelectionMode && ( - - {props.route.options.map(option => ( - - - - ))} + {props.route.params.subtitle} + + )} + {isSelectionMode && ( + + selectAll()} + > + Select all + + exitSelectionMode()} + > + Unselect + )} - - )} - {props.route.params.subtitle && ( - - {props.route.params.subtitle} - - )} - {isSelectionMode && ( - - selectAll()}> - Select all - - exitSelectionMode()} - > - Unselect - - + )} {props.route.component && ( diff --git a/apps/web/src/navigation/navigators/nbnavigator.js b/apps/web/src/navigation/navigators/nbnavigator.js index 326a57ff5..79cf5436c 100644 --- a/apps/web/src/navigation/navigators/nbnavigator.js +++ b/apps/web/src/navigation/navigators/nbnavigator.js @@ -4,7 +4,10 @@ import { createRoute } from "../routes"; import SelectionModeOptions from "../../common/selectionoptions"; const routes = { - ...createRoute("notebooks", Notebooks, { title: "Notebooks" }), + ...createRoute("notebooks", Notebooks, { + title: "Notebooks", + options: SelectionModeOptions.NotebooksOptions + }), ...createRoute("topics", Topics, { options: SelectionModeOptions.TopicOptions }), diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index ca3335b78..01bbf3f94 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -37,8 +37,7 @@ export const routes = { options: SelectionModeOptions.NotesOptions }), ...createRoute("notebooks", NotebooksContainer, { - icon: Icon.Book, - options: SelectionModeOptions.NotebooksOptions + icon: Icon.Book }), ...createNormalRoute("favorites", Notes, Icon.Star, { title: "Favorites", @@ -55,8 +54,7 @@ export const routes = { options: SelectionModeOptions.TrashOptions }), ...createRoute("tags", TagsContainer, { - icon: Icon.Tag, - options: SelectionModeOptions.NotesOptions + icon: Icon.Tag }) }; From 76bd0ebf715964915f8be32a4d9adc703def66b2 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 10:47:21 +0500 Subject: [PATCH 230/394] fix: crash when opening context menu in tags list --- apps/web/src/utils/useContextMenu.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/utils/useContextMenu.js b/apps/web/src/utils/useContextMenu.js index 88f701b85..be4521008 100644 --- a/apps/web/src/utils/useContextMenu.js +++ b/apps/web/src/utils/useContextMenu.js @@ -18,6 +18,7 @@ function contextMenuHandler(event, ref, menuId) { event.preventDefault(); const menu = document.getElementById(menuId); + if (!menu) return; menu.style.display = "block"; positionMenu(event, menu); oldOpenedMenu = menu; From 6211ebf9bcaf21f0eaef19079070dc833e690aaa Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 10:51:18 +0500 Subject: [PATCH 231/394] refactor: resolve all warnings --- apps/web/src/common/selectionoptions.js | 2 +- apps/web/src/components/list-item/index.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index b82d610cb..7381329f3 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -1,6 +1,6 @@ import * as Icon from "react-feather"; import { store as appStore } from "../stores/app-store"; -import { store as notesStore, LIST_TYPES } from "../stores/note-store"; +import { store as notesStore } from "../stores/note-store"; import { store as nbStore } from "../stores/notebook-store"; import { store as editorStore } from "../stores/editor-store"; import { db } from "./index"; diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 9371e82dc..56be6ed48 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -9,7 +9,6 @@ import { } from "../../stores/app-store"; import useContextMenu from "../../utils/useContextMenu"; import { useTheme } from "emotion-theming"; -import { isShorthandPropertyAssignment } from "typescript"; const ActionsMenu = props => ( Date: Sat, 14 Mar 2020 12:32:51 +0500 Subject: [PATCH 232/394] fix: crash when saving session --- apps/web/src/stores/editor-store.js | 4 ++-- apps/web/src/stores/note-store.js | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index da481ed7a..882b32cff 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -1,5 +1,5 @@ import createStore from "../common/store"; -import { store as noteStore, LIST_TYPES } from "./note-store"; +import { store as noteStore } from "./note-store"; import { store as appStore } from "./app-store"; import { store as tagStore } from "./tag-store"; import { db } from "../common"; @@ -137,7 +137,7 @@ function editorStore(set, get) { // we update favorites only if favorite has changed if (!oldSession || oldSession.favorite !== session.favorite) { - notesState.refreshList(LIST_TYPES.fav); + notesState.setSelectedContext({ type: "favorites" }); } }); }, diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 6ef6d470e..c3282f942 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -4,10 +4,6 @@ import { store as editorStore } from "./editor-store"; import { store as appStore } from "./app-store"; import { showPasswordDialog } from "../components/dialogs/passworddialog"; -const LIST_TYPES = { - fav: "favorites" -}; - function noteStore(set, get) { return { notes: { @@ -144,4 +140,4 @@ function setValue(set, noteId, prop, value) { const [useStore, store] = createStore(noteStore); -export { useStore, store, LIST_TYPES }; +export { useStore, store }; From c82fbf63da448b542008740127cb5817d8284659 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 14 Mar 2020 13:11:17 +0500 Subject: [PATCH 233/394] feat: add editor menu --- apps/web/src/components/editor/editor.css | 2 -- apps/web/src/components/editor/index.js | 35 ++++++++++++++++++++++- apps/web/src/utils/theme.js | 9 ++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/editor/editor.css b/apps/web/src/components/editor/editor.css index a237cf7b1..5b02fa0a6 100644 --- a/apps/web/src/components/editor/editor.css +++ b/apps/web/src/components/editor/editor.css @@ -30,10 +30,8 @@ .ql-toolbar.ql-snow { width: 100%; border: none !important; - border-bottom: 1px solid var(--border) !important; border-top: 1px solid var(--border) !important; padding: 5px !important; - padding-bottom: 10px !important; } /*Color Overrides*/ diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index 8474499ee..21ae4b71f 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useRef } from "react"; import "./editor.css"; import ReactQuill from "./react-quill"; import { Flex, Box, Text } from "rebass"; @@ -11,6 +11,7 @@ import { countWords } from "../../utils/string"; import { useTheme } from "emotion-theming"; import { useStore as useAppStore } from "../../stores/app-store"; import Animated from "../animated"; +import { Input } from "@rebass/forms"; const TextSeperator = () => { const theme = useTheme(); @@ -31,9 +32,11 @@ function Editor() { const sessionState = useStore(store => store.session.state); const setSession = useStore(store => store.setSession); const saveSession = useStore(store => store.saveSession); + const newSession = useStore(store => store.newSession); const reopenLastSession = useStore(store => store.reopenLastSession); const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); const hideProperties = useAppStore(store => store.hideProperties); + const quillRef = useRef(); useEffect(() => { // move the toolbar outside (easiest way) @@ -108,7 +111,37 @@ function Editor() { {id && id.length > 0 && <>{isSaving ? "Saving" : "Saved"}} + + newSession()}> + New + + quillRef.current.quill.history.undo()} + > + Undo + + quillRef.current.quill.history.redo()} + > + Redo + + saveSession()}> + Save + + + Export + + ({ fontFamily: "body", fontWeight: "body", fontSize: "body" + }, + menu: { + pt: 1, + pb: 2, + px: 2, + cursor: "pointer", + ":hover": { + backgroundColor: "shade" + } } }, buttons: { From dcb72c738607f2556a3360db7720acbfb4d0c667 Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Sat, 14 Mar 2020 14:43:17 +0500 Subject: [PATCH 234/394] feat: redesign settings (#132) * properties-remake * setting -sign-in * changed px to spaces * Update package.json * Update package.json * Update yarn.lock Co-authored-by: Abdullah Atta --- apps/web/src/utils/theme.js | 13 +++ apps/web/src/views/Settings.js | 153 +++++++++++++++++---------------- 2 files changed, 92 insertions(+), 74 deletions(-) diff --git a/apps/web/src/utils/theme.js b/apps/web/src/utils/theme.js index caf0d595b..20cfd52eb 100644 --- a/apps/web/src/utils/theme.js +++ b/apps/web/src/utils/theme.js @@ -186,6 +186,19 @@ const theme = (colors, shadows) => ({ px: 0, my: 0, mx: 0 + }, + setting: { + bg: "transparent", + borderBottom: "1px Solid", + borderColor: "border", + color: "text", + textAlign: "left", + fontSize: "body", + borderRadius: 0, + py: 4, + px: 4, + "&:hover": { borderColor: "primary" }, + "&:active": { color: "gray" } } }, shadows: shadows diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index 56443e35e..d17a260d1 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -1,57 +1,69 @@ import React, { useState, useEffect } from "react"; -import { Box, Button, Flex, Text } from "rebass"; +import { Box, Button, Flex, Text, Image } from "rebass"; import * as Icon from "react-feather"; import { Switch } from "@rebass/forms"; import "../app.css"; import { changeTheme, isDarkTheme, changeAccent } from "../utils/theme"; +import { useTheme } from "emotion-theming"; const Settings = props => { const [check, setCheck] = useState(isDarkTheme()); + const theme = useTheme(); return ( - - + + + + + + You are not logged in + + + Login to sync notes. + + + + + Appearance + - - {Titles.theme} + + {Titles.accent} - + {[ { label: "red", code: "#ed2d37" }, @@ -65,58 +77,51 @@ const Settings = props => { { label: "indigo", code: "#F032E6" }, { label: "lightpink", code: "#FABEBE" } ].map(color => ( - { changeAccent(color.code); }} > - - + {color.code === theme.colors.primary && ( + + )} + + ))} - - Dark Mode{" "} - - { - setCheck(!check); - changeTheme(); - }} - checked={check} - /> - - - {/* - Font Size{" "} - - - - */} + + + Dark Mode + {" "} + + { + setCheck(!check); + changeTheme(); + }} + checked={check} + /> + + + + + Other - - + + Appearance + + + + {Titles.accent} + + + + {[ + { label: "red", code: "#ed2d37" }, + { label: "orange", code: "#ec6e05" }, + { label: "yellow", code: "yellow" }, + { label: "green", code: "green" }, + { label: "blue", code: "blue" }, + { label: "purple", code: "purple" }, + { label: "gray", code: "gray" }, + { label: "lightblue", code: "#46F0F0" }, + { label: "indigo", code: "#F032E6" }, + { label: "lightpink", code: "#FABEBE" } + ].map(color => ( + { + changeAccent(color.code); + }} + > + {color.code === theme.colors.primary && ( + + )} + + + ))} + + + Dark Mode + { + setCheck(!check); + changeTheme(); + }} + checked={check} + /> + + + + Other + + + + ); }; From 585acc2c2c854e7641bb2475e14efa40f5cb18aa Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 15 Mar 2020 10:00:36 +0500 Subject: [PATCH 237/394] ui: minor improvements to settings --- apps/web/src/views/Settings.js | 37 ++++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index 33c577118..f2228facc 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -28,7 +28,7 @@ const Settings = props => { width: 40, height: 40, borderRadius: 80, - color: "secondary" + color: "static" }} > @@ -45,7 +45,7 @@ const Settings = props => { { }} py={2} > - - {Titles.accent} - - { }} justifyContent="left" mx={2} - my={2} bg="shade" p={1} > @@ -120,21 +110,24 @@ const Settings = props => { ))} - - Dark Mode - { - setCheck(!check); - changeTheme(); - }} - checked={check} - /> + { + setCheck(!check); + changeTheme(); + }} + > + {check ? "Light Mode" : "Dark Mode"} + {check ? : } Date: Sun, 15 Mar 2020 10:02:50 +0500 Subject: [PATCH 238/394] feat: remove locked note deletion from multiselect --- apps/web/src/common/selectionoptions.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 7381329f3..b6222fcfa 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -32,22 +32,7 @@ const DeleteOption = createOption(Icon.Trash2, async function(state) { const editorState = editorStore.getState(); const items = state.selectedItems.map(async item => { if (item.id === editorState.session.id) isAnyNoteOpened = true; - if (item.locked) { - if ( - !(await confirm( - Icon.Trash2, - "Delete", - "This is a locked note. Are you sure you want to delete it?" - )) || - !(await showPasswordDialog("unlock_note", password => { - return db.vault - .unlock(password) - .then(() => true) - .catch(() => false); - })) - ) - return 0; - } + if (item.locked) return 0; return item.id; }); From 6bb9b1a00fe5c500a8f5f51421a38b98fa4bff66 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 15 Mar 2020 10:43:52 +0500 Subject: [PATCH 239/394] ui: simple fade in/out animation when navigating --- apps/web/src/navigation/index.js | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 2e1052569..5ef524101 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -1,6 +1,8 @@ import React from "react"; import ReactDOM from "react-dom"; import { Box, Flex, Heading, Text } from "rebass"; +import Animated from "../components/animated"; +import { AnimatePresence } from "framer-motion"; import * as Icon from "react-feather"; import { ThemeProvider } from "../utils/theme"; import { useStore, store } from "../stores/app-store"; @@ -47,13 +49,27 @@ export default class Navigator { // exit selection mode on navigate store.getState().exitSelectionMode(); ReactDOM.render( - 0} - backAction={() => this.goBack()} - />, + + + 0 + } + backAction={() => this.goBack()} + /> + + , root ); return true; From 17d76dc9902d076908ae8322d2a84579537e00d0 Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Tue, 17 Mar 2020 12:39:49 +0500 Subject: [PATCH 240/394] feat: add remove from topic menu item (#137) * remove -note * contex menu * changes made --- apps/web/src/components/menu/index.js | 61 ++++++++++++++------------- apps/web/src/components/note/index.js | 23 +++++++++- apps/web/src/views/Notes.js | 8 +++- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index 21b0df188..7f7cd94f5 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -28,35 +28,38 @@ function Menu(props) { > Properties - {props.menuItems.map(item => ( - { - e.stopPropagation(); - Dropdown.closeLastOpened(); - if (props.closeMenu) { - props.closeMenu(); - } - if (item.onClick) { - item.onClick(props.data); - } - }} - flexDirection="row" - alignItems="center" - py={"8px"} - px={3} - sx={{ - color: item.color || "fontPrimary", - ":hover": { - backgroundColor: "shade" - } - }} - > - - {item.title} - - - ))} + {props.menuItems.map( + item => + !item.invisible && ( + { + e.stopPropagation(); + Dropdown.closeLastOpened(); + if (props.closeMenu) { + props.closeMenu(); + } + if (item.onClick) { + item.onClick(props.data); + } + }} + flexDirection="row" + alignItems="center" + py={"8px"} + px={3} + sx={{ + color: item.color || "fontPrimary", + ":hover": { + backgroundColor: "shade" + } + }} + > + + {item.title} + + + ) + )} ); diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index 910d20677..d9c66e551 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -12,7 +12,7 @@ import { showPasswordDialog } from "../dialogs/passworddialog"; import { db } from "../../common"; const dropdownRefs = []; -const menuItems = (note, index) => [ +const menuItems = (note, index, context) => [ { title: note.notebook ? "Move" : "Add to", onClick: async () => { @@ -41,6 +41,25 @@ const menuItems = (note, index) => [ } } }, + { + invisible: !context, + title: "Remove", + onClick: async () => { + confirm( + Icon.Book, + "Remove", + "Are you sure you want to Remove this note?" + ).then(async res => { + if (res) { + await db.notebooks + .notebook(context.notebook.id) + .topics.topic(context.value) + .delete(note.id); + await store.getState().setSelectedContext(context); + } + }); + } + }, { title: "Move to Trash", color: "red", @@ -113,7 +132,7 @@ function Note(props) { } pinned={props.pinnable && note.pinned} menuData={note} - menuItems={menuItems(note, index)} + menuItems={menuItems(note, index, props.context)} dropdownRefs={dropdownRefs} /> ); diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 621a171c0..7bbf89cad 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -11,6 +11,7 @@ const Notes = props => { const clearSelectedContext = useNotesStore( store => store.clearSelectedContext ); + const selectedContext = useNotesStore(store => store.selectedContext); useEffect(() => { return () => { clearSelectedContext(); @@ -21,7 +22,12 @@ const Notes = props => { type="notes" items={selectedNotes} item={(index, item) => ( - + )} button={{ content: "Make a new note", From 46241ce0891845b0362fd6ea2fe34074454908ca Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Tue, 17 Mar 2020 12:40:55 +0500 Subject: [PATCH 241/394] fix: favorites not refreshing after navigating back from search (#138) Co-authored-by: Abdullah Atta --- apps/web/src/views/Notes.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 7bbf89cad..eec980652 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -8,15 +8,7 @@ import { DEFAULT_CONTEXT } from "../common"; const Notes = props => { const newSession = useStore(store => store.newSession); const selectedNotes = useNotesStore(store => store.selectedNotes); - const clearSelectedContext = useNotesStore( - store => store.clearSelectedContext - ); const selectedContext = useNotesStore(store => store.selectedContext); - useEffect(() => { - return () => { - clearSelectedContext(); - }; - }, [clearSelectedContext]); return ( Date: Sun, 15 Mar 2020 10:50:21 +0500 Subject: [PATCH 242/394] feat: add mdi icons --- apps/web/package.json | 2 ++ apps/web/yarn.lock | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/apps/web/package.json b/apps/web/package.json index e9e1af0f3..f678f6724 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,6 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { + "@mdi/js": "^5.0.45", + "@mdi/react": "^1.3.0", "@rebass/forms": "^4.0.6", "emotion-theming": "^10.0.19", "framer-motion": "^1.9.1", diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 511e82666..bcb41df75 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -1215,6 +1215,16 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@mdi/js@^5.0.45": + version "5.0.45" + resolved "https://registry.yarnpkg.com/@mdi/js/-/js-5.0.45.tgz#50859fbbf5dda70b6f27603c9374077c2295145f" + integrity sha512-zYNV7g+nhURRTnZbFDEIm1XHWWbj6lyqFg9ZqQ72p918UuR6+L/0s1FeM57EhGmNQsCiN/Ika42H1owD91f3Iw== + +"@mdi/react@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@mdi/react/-/react-1.3.0.tgz#3d1cd84f8c56313a9c90cfa39ee49aab5c45df90" + integrity sha512-RmdB3gsAW4iXOTTHaEaGQ//2w0sxGWiZEoIDteXcf1qTkDkaA+LBu6ub4nNi4VcmSKjcceGHnYHqHENh8fky7A== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" From eae28d823b88873c4728b49c17bd6b9b2ba83f7a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 17 Mar 2020 09:09:14 +0500 Subject: [PATCH 243/394] feat: change icon pack to mdi --- apps/web/src/app.js | 20 +---- .../components/dialogs/add-notebook-dialog.js | 13 ++-- apps/web/src/components/dialogs/dialog.js | 8 +- .../components/dialogs/move-note-dialog.js | 10 ++- .../src/components/dialogs/password-dialog.js | 8 +- apps/web/src/components/editor/index.js | 7 +- apps/web/src/components/icons/index.js | 77 +++++++++++++++---- apps/web/src/components/list-item/index.js | 8 +- apps/web/src/components/note/index.js | 23 +++--- apps/web/src/components/notebook/index.js | 4 - .../placeholders/favorites-placeholder.js | 4 +- apps/web/src/components/properties/index.js | 12 +-- apps/web/src/components/search/index.js | 5 +- apps/web/src/index.css | 4 + apps/web/src/navigation/index.js | 12 ++- .../navigation/navigators/rootnavigator.js | 10 +-- apps/web/src/utils/theme.js | 8 +- apps/web/src/views/Settings.js | 24 +++--- 18 files changed, 145 insertions(+), 112 deletions(-) diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 339f4b9a0..dbede7425 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -15,25 +15,14 @@ import { useStore } from "./stores/app-store"; import { useStore as useNotesStore } from "./stores/note-store"; import { COLORS } from "./common"; import { toTitleCase } from "./utils/string"; -import * as Icon from "react-feather"; +import * as Icon from "./components/icons"; import { useStore as useAppStore } from "./stores/app-store"; import Animated from "./components/animated"; const NavMenuItem = props => { - const [fill, setFill] = useState(); - const [toggle, setToggle] = useState( - props.item.isToggled && props.item.isToggled() - ); - const theme = useTheme(); - useEffect(() => { - setFill(toggle ? theme.colors.text : props.item.color || "transparent"); - }, [props.item, toggle, theme.colors]); return ( ); -}; +} function App() { const [selectedKey, setSelectedKey] = usePersistentState( @@ -244,5 +244,4 @@ function App() { ); } - export default App; diff --git a/apps/web/src/components/button/index.js b/apps/web/src/components/button/index.js index aa882e5de..a594c6ed8 100644 --- a/apps/web/src/components/button/index.js +++ b/apps/web/src/components/button/index.js @@ -3,7 +3,7 @@ import { Flex, Text } from "rebass"; import { ButtonPressedStyle } from "../../utils/theme"; import { useTheme } from "emotion-theming"; -const Button = props => { +function Button(props) { const theme = useTheme(); return ( { ); -}; +} export default Button; diff --git a/apps/web/src/components/checkbox/index.js b/apps/web/src/components/checkbox/index.js index 6ffcfc4fd..67b8ef39f 100644 --- a/apps/web/src/components/checkbox/index.js +++ b/apps/web/src/components/checkbox/index.js @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { Flex, Text } from "rebass"; import { Switch } from "@rebass/forms"; -const CheckBox = props => { +function CheckBox(props) { const [checked, setChecked] = useState(props.checked || false); useEffect(() => { setChecked(props.checked); @@ -31,6 +31,5 @@ const CheckBox = props => { ); -}; - +} export default CheckBox; diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index d35b88d16..cf2829dd4 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -6,7 +6,7 @@ import Dialog, { showDialog } from "./dialog"; import { showSnack } from "../snackbar"; import { store } from "../../stores/notebook-store"; -export default class AddNotebookDialog extends React.Component { +class AddNotebookDialog extends React.Component { MAX_AVAILABLE_HEIGHT = window.innerHeight * 0.3; title = ""; description = ""; @@ -183,7 +183,7 @@ export default class AddNotebookDialog extends React.Component { } } -export const showEditNoteDialog = notebook => { +export function showEditNoteDialog(notebook) { return showDialog(perform => ( { }} /> )); -}; +} + +export default AddNotebookDialog; diff --git a/apps/web/src/components/dialogs/confirm.js b/apps/web/src/components/dialogs/confirm.js index d70ec6185..8f77ae039 100644 --- a/apps/web/src/components/dialogs/confirm.js +++ b/apps/web/src/components/dialogs/confirm.js @@ -22,7 +22,7 @@ function Confirm(props) { ); } -export const confirm = (icon, title, message) => { +export function confirm(icon, title, message) { return showDialog(perform => ( { onYes={() => perform(true)} /> )); -}; +} diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index d34d3115f..ef027b1c2 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -104,7 +104,7 @@ export default class Dialog extends React.Component { } } -export const showDialog = dialog => { +export function showDialog(dialog) { const root = document.getElementById("dialogContainer"); const perform = (resolve, result) => { ReactDOM.unmountComponentAtNode(root); @@ -117,4 +117,4 @@ export const showDialog = dialog => { }); } return Promise.reject("No element with id 'dialogContainer'"); -}; +} diff --git a/apps/web/src/components/dialogs/logindialog.js b/apps/web/src/components/dialogs/logindialog.js index 3e580e1a2..54d278c83 100644 --- a/apps/web/src/components/dialogs/logindialog.js +++ b/apps/web/src/components/dialogs/logindialog.js @@ -6,7 +6,7 @@ import Dialog, { showDialog } from "./dialog"; import { showSignUpDialog } from "./signupdialog"; import { useStore } from "../../stores/user-store"; -const LoginDialog = props => { +function LoginDialog(props) { const [username, setUsername] = useState(); const [password, setPassword] = useState(); const [errorMessage, setErrorMessage] = useState(); @@ -94,7 +94,7 @@ const LoginDialog = props => { } /> ); -}; +} export const showLogInDialog = () => { return showDialog(perform => perform()} />); diff --git a/apps/web/src/components/dialogs/move-note-dialog.js b/apps/web/src/components/dialogs/move-note-dialog.js index d9c68853e..9bd48ab62 100644 --- a/apps/web/src/components/dialogs/move-note-dialog.js +++ b/apps/web/src/components/dialogs/move-note-dialog.js @@ -6,7 +6,7 @@ import { db } from "../../common"; import Dialog, { showDialog } from "./dialog"; import { toTitleCase } from "../../utils/string"; -export default class MoveDialog extends React.Component { +class MoveDialog extends React.Component { history = []; _inputRef; selectedNotebook; @@ -197,7 +197,7 @@ export default class MoveDialog extends React.Component { } } -export const showMoveNoteDialog = noteIds => { +export function showMoveNoteDialog(noteIds) { return showDialog(perform => ( { onMove={() => perform(true)} /> )); -}; +} diff --git a/apps/web/src/components/dialogs/password-dialog.js b/apps/web/src/components/dialogs/password-dialog.js index 1577ea193..246e15750 100644 --- a/apps/web/src/components/dialogs/password-dialog.js +++ b/apps/web/src/components/dialogs/password-dialog.js @@ -81,7 +81,7 @@ function getDialogData(type) { } } -export const showPasswordDialog = (type, validate) => { +export function showPasswordDialog(type, validate) { const { title, icon, positiveButtonText } = getDialogData(type); return showDialog(perform => ( { onDone={() => perform(true)} /> )); -}; +} diff --git a/apps/web/src/components/dialogs/signupdialog.js b/apps/web/src/components/dialogs/signupdialog.js index e4e703702..e0ba76fc8 100644 --- a/apps/web/src/components/dialogs/signupdialog.js +++ b/apps/web/src/components/dialogs/signupdialog.js @@ -5,7 +5,7 @@ import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; import { db } from "../../common"; -const SignUpDialog = props => { +function SignUpDialog(props) { const [username, setUserName] = useState(); const [email, setEmail] = useState(); const [password, setPassword] = useState(); @@ -105,8 +105,8 @@ const SignUpDialog = props => { } /> ); -}; +} -export const showSignUpDialog = () => { +export function showSignUpDialog() { return showDialog(perform => perform()} />); -}; +} diff --git a/apps/web/src/components/dialogs/topicdialog.js b/apps/web/src/components/dialogs/topicdialog.js index 541f5884d..c65a23f08 100644 --- a/apps/web/src/components/dialogs/topicdialog.js +++ b/apps/web/src/components/dialogs/topicdialog.js @@ -6,7 +6,7 @@ import { db } from "../../common"; import Dialog, { showDialog } from "./dialog"; import { store } from "../../stores/notebook-store"; -const TopicDialog = props => { +function TopicDialog(props) { const [topic, setTopic] = useState(); return ( { negativeButton={{ text: "Cancel", onClick: props.onNo }} /> ); -}; +} -export const showTopicDialog = notebook => { +export function showTopicDialog(notebook) { return showDialog(perform => ( { }} /> )); -}; +} diff --git a/apps/web/src/components/editor/titlebox.js b/apps/web/src/components/editor/titlebox.js index 7229d161a..e9b9b9b73 100644 --- a/apps/web/src/components/editor/titlebox.js +++ b/apps/web/src/components/editor/titlebox.js @@ -5,7 +5,7 @@ import { Flex } from "rebass"; import * as Icon from "../icons"; import { store as appStore } from "../../stores/app-store"; -export default class TitleBox extends React.Component { +class TitleBox extends React.Component { state = { isFocusMode: false }; inputRef; @@ -70,3 +70,4 @@ export default class TitleBox extends React.Component { ); } } +export default TitleBox; diff --git a/apps/web/src/components/icons/index.js b/apps/web/src/components/icons/index.js index 77d78f566..eff48011f 100644 --- a/apps/web/src/components/icons/index.js +++ b/apps/web/src/components/icons/index.js @@ -4,7 +4,7 @@ import * as Icons from "@mdi/js"; import { useTheme } from "emotion-theming"; import Animated from "../animated"; -const Icon = ({ name, size = 24, color = "icon", rotate }) => { +function Icon({ name, size = 24, color = "icon", rotate }) { const theme = useTheme(); return ( { spin={rotate} /> ); -}; +} -const createIcon = name => { - return props => ( - - - - ); -}; +function createIcon(name) { + return function(props) { + return ( + + + + ); + }; +} export const Plus = createIcon(Icons.mdiPlus); export const Minus = createIcon(Icons.mdiMinus); diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index b0f08af61..c485f5820 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -7,7 +7,7 @@ import { Virtuoso as List } from "react-virtuoso"; import { useStore as useSearchStore } from "../../stores/searchstore"; import { useStore as useAppStore } from "../../stores/app-store"; -const ListContainer = props => { +function ListContainer(props) { const setSearchContext = useSearchStore(store => store.setSearchContext); const shouldSelectAll = useAppStore(store => store.shouldSelectAll); const setSelectedItems = useAppStore(store => store.setSelectedItems); @@ -68,6 +68,5 @@ const ListContainer = props => { )} ); -}; - +} export default ListContainer; diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 8c7a9b782..2480eb293 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -9,15 +9,17 @@ import { } from "../../stores/app-store"; import useContextMenu from "../../utils/useContextMenu"; -const ActionsMenu = props => ( - -); +function ActionsMenu(props) { + return ( + + ); +} function selectMenuItem(isSelected, toggleSelection) { return { @@ -51,7 +53,7 @@ const ItemSelector = ({ isSelected, toggleSelection }) => { ); }; -const ListItem = props => { +function ListItem(props) { const [parentRef, closeContextMenu] = useContextMenu( `contextMenu${props.index}` ); @@ -232,6 +234,5 @@ const ListItem = props => { )} ); -}; - +} export default ListItem; diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index fc4ce9eb2..a2564e4f7 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -13,79 +13,81 @@ import { db } from "../../common"; import { useTheme } from "emotion-theming"; const dropdownRefs = []; -const menuItems = (note, index, context) => [ - { - title: note.notebook ? "Move" : "Add to", - onClick: async () => { - if (await showMoveNoteDialog([note.id])) { - showSnack("Note moved successfully!"); - } - } - }, - { - title: note.pinned ? "Unpin" : "Pin", - onClick: () => store.getState().pin(note) - }, - { - title: note.favorite ? "Unfavorite" : "Favorite", - onClick: () => store.getState().favorite(note) - }, - { title: "Edit", onClick: () => editorStore.getState().openSession(note) }, - { - title: note.locked ? "Unlock" : "Lock", - onClick: async () => { - const { unlock, lock } = store.getState(); - if (!note.locked) { - lock(note.id); - } else { - unlock(note.id); - } - } - }, - { - invisible: context ? (context.type === "topic" ? false : true) : true, - title: "Remove", - onClick: async () => { - confirm( - Icon.Topic, - "Remove from Topic", - "Are you sure you want to remove this note?" - ).then(async res => { - if (res) { - await db.notebooks - .notebook(context.notebook.id) - .topics.topic(context.value) - .delete(note.id); - await store.getState().setSelectedContext(context); +function menuItems(note, context) { + return [ + { + title: note.notebook ? "Move" : "Add to", + onClick: async () => { + if (await showMoveNoteDialog([note.id])) { + showSnack("Note moved successfully!"); } - }); - } - }, - { - title: "Move to Trash", - color: "red", - onClick: async () => { - if (note.locked) { - const res = await showPasswordDialog("unlock_note", password => { - return db.vault - .unlock(password) - .then(() => true) - .catch(() => false); + } + }, + { + title: note.pinned ? "Unpin" : "Pin", + onClick: () => store.getState().pin(note) + }, + { + title: note.favorite ? "Unfavorite" : "Favorite", + onClick: () => store.getState().favorite(note) + }, + { title: "Edit", onClick: () => editorStore.getState().openSession(note) }, + { + title: note.locked ? "Unlock" : "Lock", + onClick: async () => { + const { unlock, lock } = store.getState(); + if (!note.locked) { + lock(note.id); + } else { + unlock(note.id); + } + } + }, + { + invisible: context ? (context.type === "topic" ? false : true) : true, + title: "Remove", + onClick: async () => { + confirm( + Icon.Topic, + "Remove from Topic", + "Are you sure you want to remove this note?" + ).then(async res => { + if (res) { + await db.notebooks + .notebook(context.notebook.id) + .topics.topic(context.value) + .delete(note.id); + await store.getState().setSelectedContext(context); + } }); - if (!res) return; } - confirm( - Icon.Trash, - "Delete", - "Are you sure you want to delete this note?" - ).then(async res => { - if (res) { - await store.getState().delete(note.id); + }, + { + title: "Move to Trash", + color: "red", + onClick: async () => { + if (note.locked) { + const res = await showPasswordDialog("unlock_note", password => { + return db.vault + .unlock(password) + .then(() => true) + .catch(() => false); + }); + if (!res) return; } - }); + confirm( + Icon.Trash, + "Delete", + "Are you sure you want to delete this note?" + ).then(async res => { + if (res) { + await store.getState().delete(note.id); + } + }); + } } - } -]; + ]; +} function Note(props) { const { item, index } = props; @@ -135,7 +137,7 @@ function Note(props) { } pinned={props.pinnable && note.pinned} menuData={note} - menuItems={menuItems(note, index, props.context)} + menuItems={menuItems(note, props.context)} dropdownRefs={dropdownRefs} /> ); diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index c3b133a4b..0f35a18e1 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -5,24 +5,25 @@ import { store } from "../../stores/notebook-store"; import { showEditNoteDialog } from "../dialogs/addnotebookdialog"; const dropdownRefs = []; +function menuItems(notebook, index) { + return [ + { + title: notebook.pinned ? "Unpin" : "Pin", + onClick: () => store.getState().pin(notebook, index) + }, + { + title: "Edit", + onClick: () => showEditNoteDialog(notebook) + }, + { + title: "Delete", + color: "red", + onClick: () => store.getState().delete(notebook.id, index) + } + ]; +} -const menuItems = (notebook, index) => [ - { - title: notebook.pinned ? "Unpin" : "Pin", - onClick: () => store.getState().pin(notebook, index) - }, - { - title: "Edit", - onClick: () => showEditNoteDialog(notebook) - }, - { - title: "Delete", - color: "red", - onClick: () => store.getState().delete(notebook.id, index) - } -]; - -export default class Notebook extends React.Component { +class Notebook extends React.Component { shouldComponentUpdate(nextProps) { const prevItem = this.props.item; const nextItem = nextProps.item; @@ -87,3 +88,4 @@ export default class Notebook extends React.Component { ); } } +export default Notebook; diff --git a/apps/web/src/components/placeholders/favorites-placeholder.js b/apps/web/src/components/placeholders/favorites-placeholder.js index 1ddda162a..f88a526aa 100644 --- a/apps/web/src/components/placeholders/favorites-placeholder.js +++ b/apps/web/src/components/placeholders/favorites-placeholder.js @@ -3,7 +3,7 @@ import React from "react"; import * as Icon from "../icons"; import { Flex, Text } from "rebass"; -const FavoritesPlaceholder = props => { +function FavoritesPlaceholder() { return ( <> { ); -}; - +} export default FavoritesPlaceholder; diff --git a/apps/web/src/components/placeholders/notebooks-placeholder.js b/apps/web/src/components/placeholders/notebooks-placeholder.js index 2d965c7db..bdbd3ffb0 100644 --- a/apps/web/src/components/placeholders/notebooks-placeholder.js +++ b/apps/web/src/components/placeholders/notebooks-placeholder.js @@ -2,7 +2,7 @@ import { motion } from "framer-motion"; import React from "react"; import { Box, Flex, Text } from "rebass"; -const NotebooksPlaceholder = props => { +function NotebooksPlaceholder() { return ( <> { ); -}; +} export default NotebooksPlaceholder; diff --git a/apps/web/src/components/placeholders/notesplacholder.js b/apps/web/src/components/placeholders/notesplacholder.js index a3e8134bf..44eea8ee0 100644 --- a/apps/web/src/components/placeholders/notesplacholder.js +++ b/apps/web/src/components/placeholders/notesplacholder.js @@ -9,7 +9,7 @@ var parameters = { opacity: "0.5" }; -const NotesPlaceholder = props => { +function NotesPlaceholder() { return ( <> { ); -}; - +} export default NotesPlaceholder; diff --git a/apps/web/src/components/placeholders/tags-placeholder.js b/apps/web/src/components/placeholders/tags-placeholder.js index 2fc3f5b35..08a1f7b53 100644 --- a/apps/web/src/components/placeholders/tags-placeholder.js +++ b/apps/web/src/components/placeholders/tags-placeholder.js @@ -40,7 +40,7 @@ const animatedTags = [ } ]; -const TagsPlaceholder = props => { +function TagsPlaceholder() { return ( <> { ); -}; - +} export default TagsPlaceholder; diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index fc3325967..987a5a38e 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -9,7 +9,7 @@ import { objectMap } from "../../utils/object"; import { useStore as useAppStore } from "../../stores/app-store"; import { motion } from "framer-motion"; -const Properties = props => { +function Properties() { const pinned = useStore(store => store.session.pinned); const favorite = useStore(store => store.session.favorite); const locked = useStore(store => store.session.locked); @@ -217,6 +217,5 @@ const Properties = props => { ) ); -}; - +} export default React.memo(Properties); diff --git a/apps/web/src/components/search/index.js b/apps/web/src/components/search/index.js index b4b37f3c9..96caf55fe 100644 --- a/apps/web/src/components/search/index.js +++ b/apps/web/src/components/search/index.js @@ -7,7 +7,7 @@ import "./search.css"; import RootNavigator from "../../navigation/navigators/rootnavigator"; var query = ""; -const Search = props => { +function Search(props) { const search = useStore(store => store.search); return ( { ); -}; +} export default Search; diff --git a/apps/web/src/components/snackbar/index.js b/apps/web/src/components/snackbar/index.js index 95d3a5fd4..909596019 100644 --- a/apps/web/src/components/snackbar/index.js +++ b/apps/web/src/components/snackbar/index.js @@ -22,29 +22,31 @@ export function showSnack(message, icon = undefined) { } } -const Snackbar = props => ( - - - {props.Icon && } - {props.message} - - -); +function Snackbar(props) { + return ( + + + {props.Icon && } + {props.message} + + + ); +} diff --git a/apps/web/src/components/topic/index.js b/apps/web/src/components/topic/index.js index e36349ef6..7aab0184f 100644 --- a/apps/web/src/components/topic/index.js +++ b/apps/web/src/components/topic/index.js @@ -9,7 +9,7 @@ const menuItems = [ } ]; -const Topic = ({ item, index, onClick }) => { +function Topic({ item, index, onClick }) { const topic = item; return ( { menuItems={menuItems} /> ); -}; - +} export default Topic; diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 275e8b175..05f33cd51 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -7,7 +7,7 @@ import * as Icon from "../components/icons"; import { ThemeProvider } from "../utils/theme"; import { useStore, store } from "../stores/app-store"; -export default class Navigator { +class Navigator { constructor(root, routes, options = {}) { this.routes = routes; this.root = root; @@ -98,8 +98,9 @@ export default class Navigator { }; } } +export default Navigator; -const NavigationContainer = props => { +function NavigationContainer(props) { const openSideMenu = useStore(store => store.openSideMenu); const isSelectionMode = useStore(store => store.isSelectionMode); const exitSelectionMode = useStore(store => store.exitSelectionMode); @@ -192,4 +193,4 @@ const NavigationContainer = props => { )} ); -}; +} diff --git a/apps/web/src/navigation/navigators/nbnavigator.js b/apps/web/src/navigation/navigators/nbnavigator.js index 79cf5436c..4d689bc33 100644 --- a/apps/web/src/navigation/navigators/nbnavigator.js +++ b/apps/web/src/navigation/navigators/nbnavigator.js @@ -13,7 +13,9 @@ const routes = { }), ...createRoute("notes", Notes, { options: SelectionModeOptions.NotesOptions }) }; + const NotebookNavigator = new Navigator("NotebookNavigator", routes, { backButtonEnabled: true }); + export default NotebookNavigator; diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index 78d076215..471f684f7 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -80,4 +80,5 @@ const RootNavigator = new Navigator( backButtonEnabled: false } ); + export default RootNavigator; diff --git a/apps/web/src/navigation/navigators/settingnavigator.js b/apps/web/src/navigation/navigators/settingnavigator.js index f3d52c5f8..9f263e9a7 100644 --- a/apps/web/src/navigation/navigators/settingnavigator.js +++ b/apps/web/src/navigation/navigators/settingnavigator.js @@ -10,7 +10,9 @@ const routes = { ...createRoute("about", TOS), ...createRoute("privacy", TOS) }; + const SettingsNavigator = new Navigator("SettingsNavigator", routes, { backButtonEnabled: true }); + export default SettingsNavigator; diff --git a/apps/web/src/navigation/navigators/tagnavigator.js b/apps/web/src/navigation/navigators/tagnavigator.js index 55f8f73db..cfed8730b 100644 --- a/apps/web/src/navigation/navigators/tagnavigator.js +++ b/apps/web/src/navigation/navigators/tagnavigator.js @@ -7,7 +7,9 @@ const routes = { ...createRoute("tags", Tags, { title: "Tags" }), ...createRoute("notes", Notes, { options: SelectionModeOptions.NotesOptions }) }; + const TagNavigator = new Navigator("TagNavigator", routes, { backButtonEnabled: true }); + export default TagNavigator; diff --git a/apps/web/src/utils/css.js b/apps/web/src/utils/css.js index d5461fbae..ba81acd54 100644 --- a/apps/web/src/utils/css.js +++ b/apps/web/src/utils/css.js @@ -13,6 +13,7 @@ export function addCss(rule) { else css.appendChild(document.createTextNode(rule)); head.insertBefore(css, getRootStylesheet()); } + function getRootStylesheet() { for (let sty of document.getElementsByTagName("style")) { if (sty.innerHTML.includes("#root")) { diff --git a/apps/web/src/utils/sample.js b/apps/web/src/utils/sample.js deleted file mode 100644 index 408ef5946..000000000 --- a/apps/web/src/utils/sample.js +++ /dev/null @@ -1,10 +0,0 @@ -export const Sample = { - text: - " Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" + - "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" + - "minim veniam, quis nostrud exercitation ullamco laboris nisi ut" + - "aliquip ex ea commodo consequat. Duis aute irure dolor in" + - "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" + - "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in" + - "culpa qui officia deserunt mollit anim id est laborum." -}; diff --git a/apps/web/src/utils/theme.js b/apps/web/src/utils/theme.js index b15ce1e8a..d4814757f 100644 --- a/apps/web/src/utils/theme.js +++ b/apps/web/src/utils/theme.js @@ -3,8 +3,8 @@ import { ThemeProvider as EmotionThemeProvider } from "emotion-theming"; import { store, useStore } from "../stores/app-store"; import { addCss } from "./css"; -const colorsLight = primary => - makeTheme({ +function colorsLight(primary) { + return makeTheme({ primary, background: "white", accent: "white", @@ -17,8 +17,10 @@ const colorsLight = primary => secondary: "white", icon: "#3b3b3b" }); -const colorsDark = primary => - makeTheme({ +} + +function colorsDark(primary) { + return makeTheme({ primary, background: "#1f1f1f", accent: "#000", @@ -31,12 +33,14 @@ const colorsDark = primary => secondary: "black", icon: "#dbdbdb" }); +} const shadowsDark = { 1: "0 0 0px 0px #00000000", 2: "0 0 8px 0px #55555544", 3: "0 0 20px 0px #55555599" }; + const shadowsLight = { 1: "0 0 20px 0px #1790F3aa", 2: "0 0 8px 0px #00000047", @@ -44,166 +48,168 @@ const shadowsLight = { 4: "0 0 5px 0px #00000017" }; -const theme = (colors, shadows) => ({ - breakpoints: ["480px", "1000px", "1000px"], - colors: colors, - space: [0, 5, 10, 12, 15], - fontSizes: { - heading: 28, - input: 14, - title: 18, - subtitle: 16, - body: 14, - menu: 14, - subBody: 11 - }, - fontWeights: { - body: 400, - heading: 700, - bold: 700 - }, - fonts: { - body: "Noto Sans JP, sans-serif", - heading: "Noto Serif, serif" - }, - sizes: { - full: "100%" - }, - radii: { - none: 0, - default: 5 - }, - forms: { - default: { - borderWidth: 0, - borderRadius: "default", - border: "2px solid", - borderColor: "border", - fontFamily: "body", - fontWeight: "body", - fontSizes: "input", - ":focus": { - outline: "none", - borderColor: "primary" +function theme(colors, shadows) { + return { + breakpoints: ["480px", "1000px", "1000px"], + colors: colors, + space: [0, 5, 10, 12, 15], + fontSizes: { + heading: 28, + input: 14, + title: 18, + subtitle: 16, + body: 14, + menu: 14, + subBody: 11 + }, + fontWeights: { + body: 400, + heading: 700, + bold: 700 + }, + fonts: { + body: "Noto Sans JP, sans-serif", + heading: "Noto Serif, serif" + }, + sizes: { + full: "100%" + }, + radii: { + none: 0, + default: 5 + }, + forms: { + default: { + borderWidth: 0, + borderRadius: "default", + border: "2px solid", + borderColor: "border", + fontFamily: "body", + fontWeight: "body", + fontSizes: "input", + ":focus": { + outline: "none", + borderColor: "primary" + }, + ":hover": { + borderColor: "hover" + } }, - ":hover": { - borderColor: "hover" + search: { + variant: "forms.default", + ":focus": { + outline: "none", + boxShadow: 4 + } + }, + error: { + variant: "forms.default", + borderColor: "red", + ":focus": { + outline: "none", + borderColor: "red" + }, + ":hover": { + borderColor: "red" + } } }, - search: { - variant: "forms.default", - ":focus": { - outline: "none", - boxShadow: 4 + text: { + heading: { + fontFamily: "heading", + fontWeight: "heading", + fontSize: "heading", + color: "text" + }, + title: { + fontFamily: "heading", + fontWeight: "bold", + fontSize: "title" + }, + body: { + fontFamily: "body", + fontWeight: "body", + fontSize: "body" + }, + menu: { + pt: 1, + pb: 2, + px: 2, + cursor: "pointer", + ":hover": { + backgroundColor: "shade" + } } }, - error: { - variant: "forms.default", - borderColor: "red", - ":focus": { - outline: "none", - borderColor: "red" + buttons: { + primary: { + color: "fontSecondary", + bg: "primary", + borderRadius: "default", + fontFamily: "body", + fontWeight: "body", + ":focus": { + outline: "none" + }, + ":hover": { + cursor: "pointer" + }, + ...ButtonPressedStyle }, - ":hover": { - borderColor: "red" - } - } - }, - text: { - heading: { - fontFamily: "heading", - fontWeight: "heading", - fontSize: "heading", - color: "text" - }, - title: { - fontFamily: "heading", - fontWeight: "bold", - fontSize: "title" - }, - body: { - fontFamily: "body", - fontWeight: "body", - fontSize: "body" - }, - menu: { - pt: 1, - pb: 2, - px: 2, - cursor: "pointer", - ":hover": { - backgroundColor: "shade" - } - } - }, - buttons: { - primary: { - color: "fontSecondary", - bg: "primary", - borderRadius: "default", - fontFamily: "body", - fontWeight: "body", - ":focus": { - outline: "none" + secondary: { + variant: "buttons.primary", + color: "text", + bg: "navbg", + ...ButtonPressedStyle }, - ":hover": { - cursor: "pointer" + tertiary: { + variant: "buttons.primary", + color: "text", + bg: "transparent", + border: "2px solid", + borderColor: "border", + ":active": { + color: "primary", + opacity: 0.8 + } }, - ...ButtonPressedStyle - }, - secondary: { - variant: "buttons.primary", - color: "text", - bg: "navbg", - ...ButtonPressedStyle - }, - tertiary: { - variant: "buttons.primary", - color: "text", - bg: "transparent", - border: "2px solid", - borderColor: "border", - ":active": { + nav: { + bg: "transparent", + fontFamily: "body", + fontWeight: "body", + ":focus": { + outline: "none" + } + }, + links: { + variant: "buttons.primary", + bg: "transparent", color: "primary", - opacity: 0.8 + fontSize: "subBody", + fontFamily: "body", + py: 0, + px: 0, + my: 0, + mx: 0 + }, + setting: { + bg: "transparent", + borderBottom: "1px Solid", + borderColor: "border", + color: "text", + textAlign: "left", + fontSize: "body", + borderRadius: 0, + py: 2, + px: 2, + outline: "none", + ":hover": { borderColor: "primary" }, + ":active": { color: "gray" } } }, - nav: { - bg: "transparent", - fontFamily: "body", - fontWeight: "body", - ":focus": { - outline: "none" - } - }, - links: { - variant: "buttons.primary", - bg: "transparent", - color: "primary", - fontSize: "subBody", - fontFamily: "body", - py: 0, - px: 0, - my: 0, - mx: 0 - }, - setting: { - bg: "transparent", - borderBottom: "1px Solid", - borderColor: "border", - color: "text", - textAlign: "left", - fontSize: "body", - borderRadius: 0, - py: 2, - px: 2, - outline: "none", - ":hover": { borderColor: "primary" }, - ":active": { color: "gray" } - } - }, - shadows: shadows -}); + shadows: shadows + }; +} function makeTheme({ primary, @@ -242,20 +248,19 @@ function makeTheme({ }; } -const getTheme = (type, accent) => - type === "dark" +function getTheme(type, accent) { + return type === "dark" ? theme(colorsDark(accent), shadowsDark) : theme(colorsLight(accent), shadowsLight); +} var currentTheme = window.localStorage.getItem("theme") || "light"; var currentAccent = window.localStorage.getItem("accent") || "#0560ff"; -export const ThemeProvider = props => { +export function ThemeProvider(props) { let theme = useStore(store => store.theme); - theme = theme.colors ? theme : getTheme(currentTheme, currentAccent); addCss(cssTheme(theme)); - return ( {props.children instanceof Function @@ -263,25 +268,27 @@ export const ThemeProvider = props => { : props.children} ); -}; +} -export const changeAccent = accent => { +export function changeAccent(accent) { currentAccent = accent; window.localStorage.setItem("accent", accent); const theme = getTheme(currentTheme, currentAccent); addCss(cssTheme(theme)); store.getState().setTheme(theme); -}; +} -export const changeTheme = () => { +export function changeTheme() { currentTheme = currentTheme === "dark" ? "light" : "dark"; window.localStorage.setItem("theme", currentTheme); const theme = getTheme(currentTheme, currentAccent); addCss(cssTheme(theme)); store.getState().setTheme(theme); -}; +} -export const isDarkTheme = () => currentTheme === "dark"; +export function isDarkTheme() { + return currentTheme === "dark"; +} export const ButtonPressedStyle = { ":active": { @@ -289,15 +296,15 @@ export const ButtonPressedStyle = { } }; -const cssTheme = theme => { +function cssTheme(theme) { let root = ":root {"; for (let color in theme.colors) { root += `--${color}: ${theme.colors[color]};`; } return root + "}"; -}; +} -const hexToRGB = (hex, alpha = 1) => { +function hexToRGB(hex, alpha = 1) { let parseString = hex; if (hex.startsWith("#")) { parseString = hex.slice(1, 7); @@ -312,4 +319,4 @@ const hexToRGB = (hex, alpha = 1) => { return null; } return `rgba(${r}, ${g}, ${b}, ${alpha})`; -}; +} diff --git a/apps/web/src/utils/time.js b/apps/web/src/utils/time.js index b6550ff22..e3a496252 100644 --- a/apps/web/src/utils/time.js +++ b/apps/web/src/utils/time.js @@ -7,6 +7,7 @@ const days = [ "Friday", "Saturday" ]; + const months = [ "Jan", "Feb", @@ -21,7 +22,8 @@ const months = [ "Nov", "Dec" ]; -export const timeConverter = timestamp => { + +export function timeConverter(timestamp) { if (!timestamp) return; var d = new Date(timestamp), // Convert the passed timestamp to milliseconds yyyy = d.getFullYear(), @@ -60,4 +62,4 @@ export const timeConverter = timestamp => { ampm; return time; -}; +} diff --git a/apps/web/src/views/General.js b/apps/web/src/views/General.js deleted file mode 100644 index 15f69e25e..000000000 --- a/apps/web/src/views/General.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import { Flex, Button } from "rebass"; - -function General() { - return ( - - - - - - - ); -} - -export default General; diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 3a7826e66..1c7451a31 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -7,7 +7,7 @@ import ListContainer from "../components/list-container"; import { useStore, store } from "../stores/notebook-store"; import NotebooksPlaceholder from "../components/placeholders/notebooks-placeholder"; -const Notebooks = props => { +function Notebooks(props) { const [open, setOpen] = useState(false); useEffect(() => store.getState().refresh(), []); const notebooks = useStore(state => state.notebooks); @@ -59,9 +59,9 @@ const Notebooks = props => { /> ); -}; +} -const NotebooksContainer = () => { +function NotebooksContainer() { useEffect(() => { const NotebookNavigator = require("../navigation/navigators/nbnavigator") .default; @@ -76,6 +76,6 @@ const NotebooksContainer = () => { flex="1 1 auto" /> ); -}; +} export { NotebooksContainer, Notebooks }; diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 1d481d930..75053d630 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -5,7 +5,7 @@ import { useStore } from "../stores/editor-store"; import { useStore as useNotesStore } from "../stores/note-store"; import { DEFAULT_CONTEXT } from "../common"; -const Notes = props => { +function Notes(props) { const newSession = useStore(store => store.newSession); const selectedNotes = useNotesStore(store => store.selectedNotes); const selectedContext = useNotesStore(store => store.selectedContext); @@ -31,6 +31,5 @@ const Notes = props => { }} /> ); -}; - +} export default Notes; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index bb9930dfb..0dc3e2710 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -6,7 +6,7 @@ import { changeTheme, isDarkTheme, changeAccent } from "../utils/theme"; import { useTheme } from "emotion-theming"; import { useStore as useUserStore } from "../stores/user-store"; -const Settings = props => { +function Settings(props) { const [check, setCheck] = useState(isDarkTheme()); const theme = useTheme(); const user = useUserStore(store => store.user); @@ -176,9 +176,9 @@ const Settings = props => { ); -}; +} -const SettingsContainer = props => { +function SettingsContainer() { useEffect(() => { const SettingsNavigator = require("../navigation/navigators/settingnavigator") .default; @@ -193,7 +193,7 @@ const SettingsContainer = props => { flex="1 1 auto" /> ); -}; +} const Titles = { general: "General", diff --git a/apps/web/src/views/TOS.js b/apps/web/src/views/TOS.js deleted file mode 100644 index dab7dd879..000000000 --- a/apps/web/src/views/TOS.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import { Text, Flex } from "rebass"; -import { Sample } from "../utils/sample"; - -function TOS() { - return ( - - - {Sample.text} - - - ); -} - -export default TOS; diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index e1c8f044b..484a88ce8 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -6,16 +6,18 @@ import { useStore as useNotesStore } from "../stores/note-store"; import { useStore, store } from "../stores/tag-store"; import TagsPlaceholder from "../components/placeholders/tags-placeholder"; -const TagNode = ({ title }) => ( - - - {"#"} +function TagNode({ title }) { + return ( + + + {"#"} + + {title} - {title} - -); + ); +} -const Tags = props => { +function Tags(props) { const setSelectedContext = useNotesStore(store => store.setSelectedContext); const tags = useStore(store => store.tags); useEffect(() => { @@ -47,9 +49,9 @@ const Tags = props => { placeholder={TagsPlaceholder} /> ); -}; +} -const TagsContainer = () => { +function TagsContainer() { useEffect(() => { const TagNavigator = require("../navigation/navigators/tagnavigator") .default; @@ -60,6 +62,6 @@ const TagsContainer = () => { return ( ); -}; +} export { Tags, TagsContainer }; diff --git a/apps/web/src/views/Topics.js b/apps/web/src/views/Topics.js index 060897cdb..5f4c181d8 100644 --- a/apps/web/src/views/Topics.js +++ b/apps/web/src/views/Topics.js @@ -6,7 +6,7 @@ import { useStore as useNoteStore } from "../stores/note-store"; import { useStore as useNbStore } from "../stores/notebook-store"; import { showTopicDialog } from "../components/dialogs/topicdialog"; -const Topics = props => { +function Topics(props) { const setSelectedContext = useNoteStore(store => store.setSelectedContext); const setSelectedNotebookTopics = useNbStore( store => store.setSelectedNotebookTopics @@ -55,6 +55,5 @@ const Topics = props => { }} /> ); -}; - +} export default Topics; diff --git a/apps/web/src/views/Trash.js b/apps/web/src/views/Trash.js index 592c18c9c..44d8fb621 100644 --- a/apps/web/src/views/Trash.js +++ b/apps/web/src/views/Trash.js @@ -9,27 +9,29 @@ import { useStore, store } from "../stores/trash-store"; import { toTitleCase } from "../utils/string"; const dropdownRefs = []; -const menuItems = (item, index) => [ - { - title: "Restore", - onClick: () => store.getState().restore(item.id, index) - }, - { - title: "Delete", - color: "red", - onClick: () => { - confirm( - Icon.Trash, - "Delete", - `Are you sure you want to permanently delete this item?` - ).then(async res => { - if (res) { - await store.getState().delete(item.id, index); - } - }); +function menuItems(item, index) { + return [ + { + title: "Restore", + onClick: () => store.getState().restore(item.id, index) + }, + { + title: "Delete", + color: "red", + onClick: () => { + confirm( + Icon.Trash, + "Delete", + `Are you sure you want to permanently delete this item?` + ).then(async res => { + if (res) { + await store.getState().delete(item.id, index); + } + }); + } } - } -]; + ]; +} function Trash() { useEffect(() => store.getState().refresh(), []); @@ -78,5 +80,4 @@ function Trash() { /> ); } - export default Trash; From e6a3400d9d6461924ec73ef083238f3f24ff4a18 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 12:02:25 +0500 Subject: [PATCH 264/394] fix: make app compile --- apps/web/src/navigation/navigators/settingnavigator.js | 8 ++------ apps/web/src/views/index.js | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/web/src/navigation/navigators/settingnavigator.js b/apps/web/src/navigation/navigators/settingnavigator.js index 9f263e9a7..ca9465df0 100644 --- a/apps/web/src/navigation/navigators/settingnavigator.js +++ b/apps/web/src/navigation/navigators/settingnavigator.js @@ -1,14 +1,10 @@ -import { Settings, Account, General, TOS } from "../../views"; +import { Settings, Account } from "../../views"; import Navigator from "../index"; import { createRoute } from "../routes"; const routes = { ...createRoute("settings", Settings, { title: "Settings" }), - ...createRoute("account", Account, { title: "Account" }), - ...createRoute("general", General), - ...createRoute("TOS", TOS), - ...createRoute("about", TOS), - ...createRoute("privacy", TOS) + ...createRoute("account", Account, { title: "Account" }) }; const SettingsNavigator = new Navigator("SettingsNavigator", routes, { diff --git a/apps/web/src/views/index.js b/apps/web/src/views/index.js index 544a38ad1..cc9df9f44 100644 --- a/apps/web/src/views/index.js +++ b/apps/web/src/views/index.js @@ -7,8 +7,6 @@ export const Settings = require("./Settings").Settings; export const Trash = require("./Trash").default; export const Account = require("./Account").default; export const SettingsContainer = require("./Settings").SettingsContainer; -export const General = require("./General").default; -export const TOS = require("./TOS").default; export const Tags = require("./Tags").Tags; export const TagsContainer = require("./Tags").TagsContainer; export const Search = require("./Search").default; From 4a51c6b9eef3636fae2ab740cb919d59d4b6f545 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 15:57:49 +0500 Subject: [PATCH 265/394] refactor: migrate theming logic to factory pattern --- .../src/components/theme-provider/index.js | 18 + apps/web/src/stores/app-store.js | 6 - apps/web/src/stores/theme-store.js | 22 ++ apps/web/src/theme/colorscheme/dark.js | 24 ++ apps/web/src/theme/colorscheme/index.js | 14 + apps/web/src/theme/colorscheme/light.js | 24 ++ apps/web/src/theme/colorscheme/static.js | 12 + apps/web/src/theme/font/fontsize.js | 14 + apps/web/src/theme/font/index.js | 18 + apps/web/src/theme/index.js | 24 ++ apps/web/src/theme/transformer/css.js | 8 + apps/web/src/theme/transformer/index.js | 12 + apps/web/src/theme/variants/button.js | 94 +++++ apps/web/src/theme/variants/index.js | 14 + apps/web/src/theme/variants/input.js | 45 +++ apps/web/src/theme/variants/text.js | 46 +++ apps/web/src/utils/color.js | 18 + apps/web/src/utils/css.js | 2 +- apps/web/src/utils/theme.js | 322 ------------------ 19 files changed, 408 insertions(+), 329 deletions(-) create mode 100644 apps/web/src/components/theme-provider/index.js create mode 100644 apps/web/src/stores/theme-store.js create mode 100644 apps/web/src/theme/colorscheme/dark.js create mode 100644 apps/web/src/theme/colorscheme/index.js create mode 100644 apps/web/src/theme/colorscheme/light.js create mode 100644 apps/web/src/theme/colorscheme/static.js create mode 100644 apps/web/src/theme/font/fontsize.js create mode 100644 apps/web/src/theme/font/index.js create mode 100644 apps/web/src/theme/index.js create mode 100644 apps/web/src/theme/transformer/css.js create mode 100644 apps/web/src/theme/transformer/index.js create mode 100644 apps/web/src/theme/variants/button.js create mode 100644 apps/web/src/theme/variants/index.js create mode 100644 apps/web/src/theme/variants/input.js create mode 100644 apps/web/src/theme/variants/text.js create mode 100644 apps/web/src/utils/color.js delete mode 100644 apps/web/src/utils/theme.js diff --git a/apps/web/src/components/theme-provider/index.js b/apps/web/src/components/theme-provider/index.js new file mode 100644 index 000000000..7f795ba74 --- /dev/null +++ b/apps/web/src/components/theme-provider/index.js @@ -0,0 +1,18 @@ +import React from "react"; +import { ThemeProvider as EmotionThemeProvider } from "emotion-theming"; +import { useStore } from "../../stores/theme-store"; +import ThemeFactory from "../../theme"; +import { injectCss } from "../../utils/css"; + +function ThemeProvider(props) { + const theme = useStore(store => store.theme); + const accent = useStore(store => store.accent); + const factory = new ThemeFactory({ theme, accent, scale: 1 }); + injectCss(factory.transform("css")); + return ( + + {props.children} + + ); +} +export default ThemeProvider; diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js index c1946c7ac..8e519037a 100644 --- a/apps/web/src/stores/app-store.js +++ b/apps/web/src/stores/app-store.js @@ -13,7 +13,6 @@ function appStore(set, get) { isSelectionMode: false, shouldSelectAll: false, selectedItems: [], - theme: {}, colors: [], refreshApp: function() { noteStore.getState().refresh(); @@ -106,11 +105,6 @@ function appStore(set, get) { .then(() => true) .catch(() => false); }); - }, - setTheme: function(theme) { - set(state => { - state.theme = theme; - }); } }; } diff --git a/apps/web/src/stores/theme-store.js b/apps/web/src/stores/theme-store.js new file mode 100644 index 000000000..0a7a0b6b9 --- /dev/null +++ b/apps/web/src/stores/theme-store.js @@ -0,0 +1,22 @@ +import createStore from "../common/store"; + +function themeStore(set) { + return { + theme: "light", + accent: "#0560ff", + setTheme: function(theme) { + set(state => { + state.theme = theme; + }); + }, + setAccent: function(accent) { + set(state => { + state.accent = accent; + }); + } + }; +} + +const [useStore, store] = createStore(themeStore); + +export { useStore, store }; diff --git a/apps/web/src/theme/colorscheme/dark.js b/apps/web/src/theme/colorscheme/dark.js new file mode 100644 index 000000000..565711054 --- /dev/null +++ b/apps/web/src/theme/colorscheme/dark.js @@ -0,0 +1,24 @@ +import { hexToRGB } from "../../utils/color"; +import StaticColorSchemeFactory from "./static"; + +class DarkColorSchemeFactory { + constructor(accent) { + return { + primary: accent, + shade: hexToRGB(accent, 0.1), + placeholder: hexToRGB("#ffffff", 0.6), + background: "#1f1f1f", + accent: "#000", + bgSecondary: "#2b2b2b", + border: "#2b2b2b", + hover: "#3b3b3b", + fontSecondary: "#000", + text: "#ffffff", + overlay: "rgba(255, 255, 255, 0.5)", + secondary: "black", + icon: "#dbdbdb", + ...new StaticColorSchemeFactory() + }; + } +} +export default DarkColorSchemeFactory; diff --git a/apps/web/src/theme/colorscheme/index.js b/apps/web/src/theme/colorscheme/index.js new file mode 100644 index 000000000..da949d1d9 --- /dev/null +++ b/apps/web/src/theme/colorscheme/index.js @@ -0,0 +1,14 @@ +import DarkColorSchemeFactory from "./dark"; +import LightColorSchemeFactory from "./light"; + +const colorSchemes = { + dark: DarkColorSchemeFactory, + light: LightColorSchemeFactory +}; + +class ColorSchemeFactory { + constructor(theme, accent) { + return colorSchemes[theme](accent); + } +} +export default ColorSchemeFactory; diff --git a/apps/web/src/theme/colorscheme/light.js b/apps/web/src/theme/colorscheme/light.js new file mode 100644 index 000000000..16ae7f9a4 --- /dev/null +++ b/apps/web/src/theme/colorscheme/light.js @@ -0,0 +1,24 @@ +import { hexToRGB } from "../../utils/color"; +import StaticColorSchemeFactory from "./static"; + +class LightColorSchemeFactory { + constructor(accent) { + return { + primary: accent, + background: "white", + accent: "white", + bgSecondary: "#f0f0f0", + border: "#f0f0f0", + hover: "#e0e0e0", + fontSecondary: "white", + text: "#000000", + overlay: "rgba(0, 0, 0, 0.1)", + secondary: "white", + icon: "#3b3b3b", + shade: hexToRGB(accent, 0.1), + placeholder: hexToRGB("#000000", 0.6), + ...new StaticColorSchemeFactory() + }; + } +} +export default LightColorSchemeFactory; diff --git a/apps/web/src/theme/colorscheme/static.js b/apps/web/src/theme/colorscheme/static.js new file mode 100644 index 000000000..2cd6ee339 --- /dev/null +++ b/apps/web/src/theme/colorscheme/static.js @@ -0,0 +1,12 @@ +class StaticColorSchemeFactory { + constructor() { + return { + fontTertiary: "gray", + transparent: "transparent", + static: "white", + error: "red", + favorite: "#ffd700" + }; + } +} +export default StaticColorSchemeFactory; diff --git a/apps/web/src/theme/font/fontsize.js b/apps/web/src/theme/font/fontsize.js new file mode 100644 index 000000000..c1162c2c0 --- /dev/null +++ b/apps/web/src/theme/font/fontsize.js @@ -0,0 +1,14 @@ +class FontSizeFactory { + constructor(scaleFactor) { + return { + heading: 28 * scaleFactor, + input: 14 * scaleFactor, + title: 18 * scaleFactor, + subtitle: 16 * scaleFactor, + body: 14 * scaleFactor, + menu: 14 * scaleFactor, + subBody: 11 * scaleFactor + }; + } +} +export default FontSizeFactory; diff --git a/apps/web/src/theme/font/index.js b/apps/web/src/theme/font/index.js new file mode 100644 index 000000000..210db6d8f --- /dev/null +++ b/apps/web/src/theme/font/index.js @@ -0,0 +1,18 @@ +import FontSizeFactory from "./fontsize"; + +class FontFactory { + constructor(scale) { + return { + fontSizes: new FontSizeFactory(scale), + fontWeights: { + body: 400, + bold: 700 + }, + fonts: { + body: "Noto Sans JP, sans-serif", + heading: "Noto Serif, serif" + } + }; + } +} +export default FontFactory; diff --git a/apps/web/src/theme/index.js b/apps/web/src/theme/index.js new file mode 100644 index 000000000..b56885c7d --- /dev/null +++ b/apps/web/src/theme/index.js @@ -0,0 +1,24 @@ +import ColorSchemeFactory from "./colorscheme"; +import VariantsFactory from "./variants"; +import FontFactory from "./font"; +import TransformerFactory from "./transformer"; + +class ThemeFactory { + constructor(config) { + return { + breakpoints: ["480px", "1000px", "1000px"], + space: [0, 5, 10, 15, 20, 25, 30, 35], + sizes: { full: "100%", half: "50%" }, + radii: { none: 0, default: 5 }, + colors: new ColorSchemeFactory(config.theme, config.accent), + ...new FontFactory(config.scale), + ...new VariantsFactory() + }; + } + + transform(type) { + return new TransformerFactory(type, this); + } +} + +export default ThemeFactory; diff --git a/apps/web/src/theme/transformer/css.js b/apps/web/src/theme/transformer/css.js new file mode 100644 index 000000000..71588bea3 --- /dev/null +++ b/apps/web/src/theme/transformer/css.js @@ -0,0 +1,8 @@ +function transform(theme) { + let root = ":root {"; + for (let color in theme.colors) { + root += `--${color}: ${theme.colors[color]};`; + } + return root + "}"; +} +export default transform; diff --git a/apps/web/src/theme/transformer/index.js b/apps/web/src/theme/transformer/index.js new file mode 100644 index 000000000..8b5e2424a --- /dev/null +++ b/apps/web/src/theme/transformer/index.js @@ -0,0 +1,12 @@ +import css from "./css"; + +const transformers = { + css: css +}; + +class TransformerFactory { + constructor(type, theme) { + return transformers[type](theme); + } +} +export default TransformerFactory; diff --git a/apps/web/src/theme/variants/button.js b/apps/web/src/theme/variants/button.js new file mode 100644 index 000000000..ef1b04ef3 --- /dev/null +++ b/apps/web/src/theme/variants/button.js @@ -0,0 +1,94 @@ +class ButtonFactory { + constructor() { + return { + default: new Default(), + primary: new Primary(), + secondary: new Secondary(), + tertiary: new Tertiary(), + list: new List(), + anchor: new Anchor(), + menu: new Menu() + }; + } +} +export default ButtonFactory; + +class Default { + constructor() { + return { + fontFamily: "body", + fontWeight: "body", + borderRadius: "default", + ":focus": { + outline: "none" + }, + ":hover": { + cursor: "pointer" + } + }; + } +} + +class Primary { + constructor() { + return { + variant: "buttons.default", + color: "fontSecondary", + bg: "primary" + }; + } +} + +class Secondary { + constructor() { + return { variant: "buttons.default", color: "text", bg: "bgSecondary" }; + } +} + +class Tertiary { + constructor() { + return { + variant: "buttons.default", + color: "text", + bg: "transparent", + border: "2px solid", + borderColor: "border" + }; + } +} + +class List { + constructor() { + return { + variant: "buttons.tertiary", + border: "0px solid", + borderBottom: "1px solid", + borderRadius: 0, + p: 2 + }; + } +} + +class Anchor { + constructor() { + return { + variant: "button.default", + color: "primary", + fontSize: "subBody", + p: 0, + m: 0 + }; + } +} + +class Menu { + constructor() { + return { + variant: "button.default", + cursor: "pointer", + ":hover": { + backgroundColor: "shade" + } + }; + } +} diff --git a/apps/web/src/theme/variants/index.js b/apps/web/src/theme/variants/index.js new file mode 100644 index 000000000..1b080939b --- /dev/null +++ b/apps/web/src/theme/variants/index.js @@ -0,0 +1,14 @@ +import ButtonFactory from "./button"; +import InputFactory from "./input"; +import TextFactory from "./text"; + +class VariantFactory { + constructor() { + return { + buttons: new ButtonFactory(), + forms: new InputFactory(), + text: new TextFactory() + }; + } +} +export default VariantFactory; diff --git a/apps/web/src/theme/variants/input.js b/apps/web/src/theme/variants/input.js new file mode 100644 index 000000000..2d7eaf231 --- /dev/null +++ b/apps/web/src/theme/variants/input.js @@ -0,0 +1,45 @@ +class InputFactory { + constructor() { + return { + default: new Default(), + error: new Error() + }; + } +} +export default InputFactory; + +class Default { + constructor() { + return { + borderRadius: "default", + border: "2px solid", + borderColor: "border", + fontFamily: "body", + fontWeight: "body", + fontSize: "input", + ":focus": { + outline: "none", + borderColor: "primary" + }, + ":hover": { + borderColor: "shade" + } + }; + } +} + +class Error { + constructor() { + return { + variant: "forms.default", + borderColor: "red", + ":focus": { + outline: "none", + borderColor: "red" + }, + ":hover": { + borderColor: "darkred" + } + }; + } +} diff --git a/apps/web/src/theme/variants/text.js b/apps/web/src/theme/variants/text.js new file mode 100644 index 000000000..d1fc1b3d8 --- /dev/null +++ b/apps/web/src/theme/variants/text.js @@ -0,0 +1,46 @@ +class TextFactory { + constructor() { + return { + default: new Default(), + heading: new Heading(), + title: new Title(), + body: new Body() + }; + } +} +export default TextFactory; + +class Default { + constructor() { + return { + color: "text", + fontFamily: "body" + }; + } +} + +class Heading { + constructor() { + return { + variant: "text.default", + fontFamily: "heading", + fontWeight: "bold", + fontSize: "heading" + }; + } +} + +class Title { + constructor() { + return { + variant: "text.heading", + fontSize: "title" + }; + } +} + +class Body { + constructor() { + return { variant: "text.default", fontWeight: "body", fontSize: "body" }; + } +} diff --git a/apps/web/src/utils/color.js b/apps/web/src/utils/color.js new file mode 100644 index 000000000..dc5ee9803 --- /dev/null +++ b/apps/web/src/utils/color.js @@ -0,0 +1,18 @@ +function hexToRGB(hex, alpha = 1) { + let parseString = hex; + if (hex.startsWith("#")) { + parseString = hex.slice(1, 7); + } + if (parseString.length !== 6) { + return null; + } + const r = parseInt(parseString.slice(0, 2), 16); + const g = parseInt(parseString.slice(2, 4), 16); + const b = parseInt(parseString.slice(4, 6), 16); + if (isNaN(r) || isNaN(g) || isNaN(b)) { + return null; + } + return `rgba(${r}, ${g}, ${b}, ${alpha})`; +} + +export { hexToRGB }; diff --git a/apps/web/src/utils/css.js b/apps/web/src/utils/css.js index ba81acd54..78a7e5ab1 100644 --- a/apps/web/src/utils/css.js +++ b/apps/web/src/utils/css.js @@ -1,4 +1,4 @@ -export function addCss(rule) { +export function injectCss(rule) { let variableCss = document.getElementById("variables"); let head = document.getElementsByTagName("head")[0]; if (variableCss) { diff --git a/apps/web/src/utils/theme.js b/apps/web/src/utils/theme.js deleted file mode 100644 index d4814757f..000000000 --- a/apps/web/src/utils/theme.js +++ /dev/null @@ -1,322 +0,0 @@ -import React from "react"; -import { ThemeProvider as EmotionThemeProvider } from "emotion-theming"; -import { store, useStore } from "../stores/app-store"; -import { addCss } from "./css"; - -function colorsLight(primary) { - return makeTheme({ - primary, - background: "white", - accent: "white", - navbg: "#f0f0f0", - border: "#f0f0f0", - hover: "#e0e0e0", - fontSecondary: "white", - text: "#000000", - overlay: "rgba(0, 0, 0, 0.1)", - secondary: "white", - icon: "#3b3b3b" - }); -} - -function colorsDark(primary) { - return makeTheme({ - primary, - background: "#1f1f1f", - accent: "#000", - navbg: "#2b2b2b", - border: "#2b2b2b", - hover: "#3b3b3b", - fontSecondary: "#000", - text: "#ffffff", - overlay: "rgba(255, 255, 255, 0.5)", - secondary: "black", - icon: "#dbdbdb" - }); -} - -const shadowsDark = { - 1: "0 0 0px 0px #00000000", - 2: "0 0 8px 0px #55555544", - 3: "0 0 20px 0px #55555599" -}; - -const shadowsLight = { - 1: "0 0 20px 0px #1790F3aa", - 2: "0 0 8px 0px #00000047", - 3: "0 0 20px 0px #aaaaaa77", - 4: "0 0 5px 0px #00000017" -}; - -function theme(colors, shadows) { - return { - breakpoints: ["480px", "1000px", "1000px"], - colors: colors, - space: [0, 5, 10, 12, 15], - fontSizes: { - heading: 28, - input: 14, - title: 18, - subtitle: 16, - body: 14, - menu: 14, - subBody: 11 - }, - fontWeights: { - body: 400, - heading: 700, - bold: 700 - }, - fonts: { - body: "Noto Sans JP, sans-serif", - heading: "Noto Serif, serif" - }, - sizes: { - full: "100%" - }, - radii: { - none: 0, - default: 5 - }, - forms: { - default: { - borderWidth: 0, - borderRadius: "default", - border: "2px solid", - borderColor: "border", - fontFamily: "body", - fontWeight: "body", - fontSizes: "input", - ":focus": { - outline: "none", - borderColor: "primary" - }, - ":hover": { - borderColor: "hover" - } - }, - search: { - variant: "forms.default", - ":focus": { - outline: "none", - boxShadow: 4 - } - }, - error: { - variant: "forms.default", - borderColor: "red", - ":focus": { - outline: "none", - borderColor: "red" - }, - ":hover": { - borderColor: "red" - } - } - }, - text: { - heading: { - fontFamily: "heading", - fontWeight: "heading", - fontSize: "heading", - color: "text" - }, - title: { - fontFamily: "heading", - fontWeight: "bold", - fontSize: "title" - }, - body: { - fontFamily: "body", - fontWeight: "body", - fontSize: "body" - }, - menu: { - pt: 1, - pb: 2, - px: 2, - cursor: "pointer", - ":hover": { - backgroundColor: "shade" - } - } - }, - buttons: { - primary: { - color: "fontSecondary", - bg: "primary", - borderRadius: "default", - fontFamily: "body", - fontWeight: "body", - ":focus": { - outline: "none" - }, - ":hover": { - cursor: "pointer" - }, - ...ButtonPressedStyle - }, - secondary: { - variant: "buttons.primary", - color: "text", - bg: "navbg", - ...ButtonPressedStyle - }, - tertiary: { - variant: "buttons.primary", - color: "text", - bg: "transparent", - border: "2px solid", - borderColor: "border", - ":active": { - color: "primary", - opacity: 0.8 - } - }, - nav: { - bg: "transparent", - fontFamily: "body", - fontWeight: "body", - ":focus": { - outline: "none" - } - }, - links: { - variant: "buttons.primary", - bg: "transparent", - color: "primary", - fontSize: "subBody", - fontFamily: "body", - py: 0, - px: 0, - my: 0, - mx: 0 - }, - setting: { - bg: "transparent", - borderBottom: "1px Solid", - borderColor: "border", - color: "text", - textAlign: "left", - fontSize: "body", - borderRadius: 0, - py: 2, - px: 2, - outline: "none", - ":hover": { borderColor: "primary" }, - ":active": { color: "gray" } - } - }, - shadows: shadows - }; -} - -function makeTheme({ - primary, - background, - accent, - navbg, - border, - hover, - fontSecondary, - text, - overlay, - secondary, - icon -}) { - return { - background, - primary, - shade: hexToRGB(primary, 0.1), - //secondary: "", - accent, - //custom - navbg, - border, - hover, - fontSecondary, - fontTertiary: "gray", - transparent: "transparent", - text, - placeholder: hexToRGB(text, 0.6), - overlay, - static: "white", - secondary, - icon, - error: "red", - favorite: "#ffd700" - }; -} - -function getTheme(type, accent) { - return type === "dark" - ? theme(colorsDark(accent), shadowsDark) - : theme(colorsLight(accent), shadowsLight); -} - -var currentTheme = window.localStorage.getItem("theme") || "light"; -var currentAccent = window.localStorage.getItem("accent") || "#0560ff"; - -export function ThemeProvider(props) { - let theme = useStore(store => store.theme); - theme = theme.colors ? theme : getTheme(currentTheme, currentAccent); - addCss(cssTheme(theme)); - return ( - - {props.children instanceof Function - ? props.children(theme) - : props.children} - - ); -} - -export function changeAccent(accent) { - currentAccent = accent; - window.localStorage.setItem("accent", accent); - const theme = getTheme(currentTheme, currentAccent); - addCss(cssTheme(theme)); - store.getState().setTheme(theme); -} - -export function changeTheme() { - currentTheme = currentTheme === "dark" ? "light" : "dark"; - window.localStorage.setItem("theme", currentTheme); - const theme = getTheme(currentTheme, currentAccent); - addCss(cssTheme(theme)); - store.getState().setTheme(theme); -} - -export function isDarkTheme() { - return currentTheme === "dark"; -} - -export const ButtonPressedStyle = { - ":active": { - opacity: "0.8" - } -}; - -function cssTheme(theme) { - let root = ":root {"; - for (let color in theme.colors) { - root += `--${color}: ${theme.colors[color]};`; - } - return root + "}"; -} - -function hexToRGB(hex, alpha = 1) { - let parseString = hex; - if (hex.startsWith("#")) { - parseString = hex.slice(1, 7); - } - if (parseString.length !== 6) { - return null; - } - const r = parseInt(parseString.slice(0, 2), 16); - const g = parseInt(parseString.slice(2, 4), 16); - const b = parseInt(parseString.slice(4, 6), 16); - if (isNaN(r) || isNaN(g) || isNaN(b)) { - return null; - } - return `rgba(${r}, ${g}, ${b}, ${alpha})`; -} From 4267237f7e43c3429455735b9909c75ef7e75a66 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 16:22:21 +0500 Subject: [PATCH 266/394] fix: make app compile after theming logic changes --- apps/web/src/app.js | 2 +- apps/web/src/components/button/index.js | 3 +- .../components/dialogs/add-notebook-dialog.js | 3 - apps/web/src/components/dialogs/dialog.js | 185 +++++++++--------- apps/web/src/components/note/index.js | 3 +- apps/web/src/components/snackbar/index.js | 52 ----- apps/web/src/navigation/index.js | 2 +- .../navigation/navigators/rootnavigator.js | 4 +- apps/web/src/stores/theme-store.js | 6 +- apps/web/src/views/Settings.js | 23 ++- 10 files changed, 113 insertions(+), 170 deletions(-) delete mode 100644 apps/web/src/components/snackbar/index.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index b588e916c..0c7ac0a10 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -3,7 +3,7 @@ import "./app.css"; import Editor from "./components/editor"; import { motion } from "framer-motion"; import { Flex, Box, Button, Text } from "rebass"; -import { ThemeProvider } from "./utils/theme"; +import ThemeProvider from "./components/theme-provider"; import RootNavigator, { bottomRoutes, routes diff --git a/apps/web/src/components/button/index.js b/apps/web/src/components/button/index.js index a594c6ed8..37416fa8f 100644 --- a/apps/web/src/components/button/index.js +++ b/apps/web/src/components/button/index.js @@ -1,8 +1,8 @@ import React from "react"; import { Flex, Text } from "rebass"; -import { ButtonPressedStyle } from "../../utils/theme"; import { useTheme } from "emotion-theming"; +//TODO use normal button function Button(props) { const theme = useTheme(); return ( @@ -24,7 +24,6 @@ function Button(props) { cursor: "pointer", bg: theme.colors.primary + "dd" }, - ...ButtonPressedStyle, ...props.style }} onClick={props.onClick} diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index cf2829dd4..216af18ee 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -3,7 +3,6 @@ import { Flex, Box, Text, Button as RebassButton } from "rebass"; import { Input } from "@rebass/forms"; import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; -import { showSnack } from "../snackbar"; import { store } from "../../stores/notebook-store"; class AddNotebookDialog extends React.Component { @@ -167,8 +166,6 @@ class AddNotebookDialog extends React.Component { positiveButton={{ text: props.edit ? "Edit" : "Add", onClick: () => { - if (!this.title.trim().length) - return showSnack("Please enter the notebook title."); props.onDone({ title: this.title, description: this.description, diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index ef027b1c2..70f19103a 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -1,108 +1,105 @@ import React from "react"; import ReactDOM from "react-dom"; import { Flex, Text, Button as RebassButton } from "rebass"; -import { ThemeProvider } from "../../utils/theme"; +import ThemeProvider from "../theme-provider"; import * as Icon from "../icons"; import Modal from "react-modal"; +import { useTheme } from "emotion-theming"; -export default class Dialog extends React.Component { - render() { - const props = this.props; - return ( - - {theme => ( - + + + - - + + {props.title} + + + {props.content} + + {props.positiveButton && ( + - - - {props.title} - - - {props.content} - - {props.positiveButton && ( - - {props.positiveButton.loading ? ( - - ) : ( - props.positiveButton.text || "OK" - )} - + {props.positiveButton.loading ? ( + + ) : ( + props.positiveButton.text || "OK" )} + + )} - {props.negativeButton && ( - - {props.negativeButton.text || "Cancel"} - - )} - - - - )} - - ); - } + {props.negativeButton && ( + + {props.negativeButton.text || "Cancel"} + + )} + + + + + ); } +export default Dialog; export function showDialog(dialog) { const root = document.getElementById("dialogContainer"); diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index a2564e4f7..f600c9497 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -2,7 +2,6 @@ import React from "react"; import { Flex, Box } from "rebass"; import * as Icon from "../icons"; import TimeAgo from "timeago-react"; -import { showSnack } from "../snackbar"; import ListItem from "../list-item"; import { confirm } from "../dialogs/confirm"; import { showMoveNoteDialog } from "../dialogs/movenotedialog"; @@ -19,7 +18,7 @@ function menuItems(note, context) { title: note.notebook ? "Move" : "Add to", onClick: async () => { if (await showMoveNoteDialog([note.id])) { - showSnack("Note moved successfully!"); + console.log("Note moved successfully!"); } } }, diff --git a/apps/web/src/components/snackbar/index.js b/apps/web/src/components/snackbar/index.js deleted file mode 100644 index 909596019..000000000 --- a/apps/web/src/components/snackbar/index.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { Flex, Text } from "rebass"; -import { ThemeProvider } from "../../utils/theme"; - -export function showSnack(message, icon = undefined) { - const root = document.getElementById("snackbarContainer"); - if (root) { - ReactDOM.render(, root); - setTimeout(() => { - const snackbar = document.getElementById("snackbar"); - if (!snackbar) return; - setTimeout(() => ReactDOM.unmountComponentAtNode(root), 700); - snackbar.animate( - { - opacity: [1, 0], - transform: ["translateY(0px)", "translateY(500px)"] - }, - 1000 - ); - }, 3000); - } -} - -function Snackbar(props) { - return ( - - - {props.Icon && } - {props.message} - - - ); -} diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 05f33cd51..0ec285ea8 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -4,7 +4,7 @@ import { Box, Flex, Heading, Text } from "rebass"; import Animated from "../components/animated"; import { AnimatePresence } from "framer-motion"; import * as Icon from "../components/icons"; -import { ThemeProvider } from "../utils/theme"; +import ThemeProvider from "../components/theme-provider"; import { useStore, store } from "../stores/app-store"; class Navigator { diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index 471f684f7..15ce57eae 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -10,16 +10,16 @@ import { import * as Icon from "../../components/icons"; import { createRoute, createNormalRoute, createDeadRoute } from "../routes"; import Navigator from "../index"; -import { changeTheme } from "../../utils/theme"; import SelectionModeOptions from "../../common/selectionoptions"; import Search from "../../views/Search"; import { store as noteStore } from "../../stores/note-store"; import { store as userStore } from "../../stores/user-store"; +import { store as themeStore } from "../../stores/theme-store"; import { showLogInDialog } from "../../components/dialogs/logindialog"; export const bottomRoutes = { ...createDeadRoute("nightmode", Icon.Theme, { - onClick: () => changeTheme() + onClick: () => themeStore.getState().toggleNightMode() }), ...createDeadRoute("sync", Icon.Sync, { onClick: async () => userStore.getState().sync(), diff --git a/apps/web/src/stores/theme-store.js b/apps/web/src/stores/theme-store.js index 0a7a0b6b9..8d71ae80a 100644 --- a/apps/web/src/stores/theme-store.js +++ b/apps/web/src/stores/theme-store.js @@ -1,6 +1,6 @@ import createStore from "../common/store"; -function themeStore(set) { +function themeStore(set, get) { return { theme: "light", accent: "#0560ff", @@ -9,6 +9,10 @@ function themeStore(set) { state.theme = theme; }); }, + toggleNightMode: function() { + const theme = get().theme; + get().setTheme(theme === "dark" ? "light" : "dark"); + }, setAccent: function(accent) { set(state => { state.accent = accent; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index 0dc3e2710..e44420454 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -1,16 +1,18 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect } from "react"; import { Box, Button, Flex, Text } from "rebass"; import * as Icon from "../components/icons"; import "../app.css"; -import { changeTheme, isDarkTheme, changeAccent } from "../utils/theme"; -import { useTheme } from "emotion-theming"; import { useStore as useUserStore } from "../stores/user-store"; +import { useStore as useThemeStore } from "../stores/theme-store"; function Settings(props) { - const [check, setCheck] = useState(isDarkTheme()); - const theme = useTheme(); + const theme = useThemeStore(store => store.theme); + const accent = useThemeStore(store => store.accent); + const toggleNightMode = useThemeStore(store => store.theme); + const setAccent = useThemeStore(store => store.theme); const user = useUserStore(store => store.user); const isLoggedIn = useUserStore(store => store.isLoggedIn); + return ( { - changeAccent(color.code); + setAccent(color.code); }} > - {color.code === theme.colors.primary && ( + {color.code === accent && ( { - setCheck(!check); - changeTheme(); - }} + onClick={() => toggleNightMode()} > Dark Mode - {check ? : } + {theme === "dark" ? : } Date: Thu, 26 Mar 2020 16:27:27 +0500 Subject: [PATCH 267/394] fix: cannot use class as a function --- apps/web/src/theme/colorscheme/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/theme/colorscheme/index.js b/apps/web/src/theme/colorscheme/index.js index da949d1d9..252386e62 100644 --- a/apps/web/src/theme/colorscheme/index.js +++ b/apps/web/src/theme/colorscheme/index.js @@ -8,7 +8,7 @@ const colorSchemes = { class ColorSchemeFactory { constructor(theme, accent) { - return colorSchemes[theme](accent); + return new colorSchemes[theme](accent); } } export default ColorSchemeFactory; From 25573d417381435c28edec020d09f035f9100c5e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 16:27:50 +0500 Subject: [PATCH 268/394] fix: ThemeFactory has no function called "transform" --- apps/web/src/components/theme-provider/index.js | 10 +++++----- apps/web/src/theme/index.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/theme-provider/index.js b/apps/web/src/components/theme-provider/index.js index 7f795ba74..e80ba09dc 100644 --- a/apps/web/src/components/theme-provider/index.js +++ b/apps/web/src/components/theme-provider/index.js @@ -4,15 +4,15 @@ import { useStore } from "../../stores/theme-store"; import ThemeFactory from "../../theme"; import { injectCss } from "../../utils/css"; +const factory = new ThemeFactory(); + function ThemeProvider(props) { - const theme = useStore(store => store.theme); + const themeType = useStore(store => store.theme); const accent = useStore(store => store.accent); - const factory = new ThemeFactory({ theme, accent, scale: 1 }); injectCss(factory.transform("css")); + const theme = factory.construct({ theme: themeType, accent, scale: 1 }); return ( - - {props.children} - + {props.children} ); } export default ThemeProvider; diff --git a/apps/web/src/theme/index.js b/apps/web/src/theme/index.js index b56885c7d..3f1c9ac50 100644 --- a/apps/web/src/theme/index.js +++ b/apps/web/src/theme/index.js @@ -4,7 +4,11 @@ import FontFactory from "./font"; import TransformerFactory from "./transformer"; class ThemeFactory { - constructor(config) { + transform(type) { + return new TransformerFactory(type, this); + } + + construct(config) { return { breakpoints: ["480px", "1000px", "1000px"], space: [0, 5, 10, 15, 20, 25, 30, 35], @@ -15,10 +19,6 @@ class ThemeFactory { ...new VariantsFactory() }; } - - transform(type) { - return new TransformerFactory(type, this); - } } export default ThemeFactory; From d7948a5df3dc12cd92b97f402a35e15404d5515f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 17:15:24 +0500 Subject: [PATCH 269/394] ui: seperate navmenuitem from app.js --- apps/web/src/app.js | 69 +++--------------------- apps/web/src/components/navitem/index.js | 40 ++++++++++++++ apps/web/src/theme/variants/button.js | 11 ++-- 3 files changed, 51 insertions(+), 69 deletions(-) create mode 100644 apps/web/src/components/navitem/index.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 0c7ac0a10..b8fd578c0 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -1,14 +1,13 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect } from "react"; import "./app.css"; import Editor from "./components/editor"; import { motion } from "framer-motion"; -import { Flex, Box, Button, Text } from "rebass"; +import { Flex, Box } from "rebass"; import ThemeProvider from "./components/theme-provider"; import RootNavigator, { bottomRoutes, routes } from "./navigation/navigators/rootnavigator"; -import "./app.css"; import { usePersistentState } from "./utils/hooks"; import { useStore } from "./stores/app-store"; import { useStore as useNotesStore } from "./stores/note-store"; @@ -18,63 +17,7 @@ import * as Icon from "./components/icons"; import { useStore as useAppStore } from "./stores/app-store"; import { useStore as useUserStore } from "./stores/user-store"; import Animated from "./components/animated"; - -function NavMenuItem(props) { - const [isLoading, setIsLoading] = useState(false); - const isSyncing = useUserStore(store => store.isSyncing); - useEffect(() => { - if (props.item.animatable) { - if (props.item.key === "sync") setIsLoading(isSyncing); - } - }, [isSyncing, setIsLoading, props.item]); - - return ( - - ); -} +import NavItem from "./components/navitem"; function App() { const [selectedKey, setSelectedKey] = usePersistentState( @@ -143,7 +86,7 @@ function App() { }} > {Object.values(routes).map((item, index) => ( - { if (selectedKey === item.key) { setShow(!show); @@ -164,7 +107,7 @@ function App() { ))} {colors.map(color => { return ( - { setSelectedKey(undefined); setSelectedContext({ @@ -193,7 +136,7 @@ function App() { {Object.values(bottomRoutes).map((item, index) => ( - { if (item.onClick) { await item.onClick(); diff --git a/apps/web/src/components/navitem/index.js b/apps/web/src/components/navitem/index.js new file mode 100644 index 000000000..1a306a24f --- /dev/null +++ b/apps/web/src/components/navitem/index.js @@ -0,0 +1,40 @@ +import React, { useState, useEffect } from "react"; +import { Flex, Button, Text } from "rebass"; +import { useStore as useUserStore } from "../../stores/user-store"; + +function NavItem(props) { + const { key, animatable, icon: Icon, color, title } = props.item; + const [isLoading, setIsLoading] = useState(false); + const isSyncing = useUserStore(store => store.isSyncing); + + useEffect(() => { + if (animatable) { + if (key === "sync") setIsLoading(isSyncing); + } + }, [isSyncing, setIsLoading, animatable, key]); + + return ( + + ); +} +export default NavItem; diff --git a/apps/web/src/theme/variants/button.js b/apps/web/src/theme/variants/button.js index ef1b04ef3..d3104963d 100644 --- a/apps/web/src/theme/variants/button.js +++ b/apps/web/src/theme/variants/button.js @@ -16,14 +16,13 @@ export default ButtonFactory; class Default { constructor() { return { + bg: "transparent", fontFamily: "body", fontWeight: "body", borderRadius: "default", + cursor: "pointer", ":focus": { outline: "none" - }, - ":hover": { - cursor: "pointer" } }; } @@ -72,7 +71,7 @@ class List { class Anchor { constructor() { return { - variant: "button.default", + variant: "buttons.default", color: "primary", fontSize: "subBody", p: 0, @@ -84,8 +83,8 @@ class Anchor { class Menu { constructor() { return { - variant: "button.default", - cursor: "pointer", + variant: "buttons.default", + borderRadius: "none", ":hover": { backgroundColor: "shade" } From 5a4f923e9a6eeade3563978f84f5a7d62a4385ac Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 26 Mar 2020 20:35:33 +0500 Subject: [PATCH 270/394] refactor: seperate navigationmenu from app.js --- apps/web/src/app.js | 155 ++---------------- .../src/components/navigation-menu/index.js | 109 ++++++++++++ .../navigation/navigators/rootnavigator.js | 12 +- 3 files changed, 126 insertions(+), 150 deletions(-) create mode 100644 apps/web/src/components/navigation-menu/index.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index b8fd578c0..0a1609a56 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -1,43 +1,25 @@ import React, { useEffect } from "react"; import "./app.css"; import Editor from "./components/editor"; -import { motion } from "framer-motion"; import { Flex, Box } from "rebass"; import ThemeProvider from "./components/theme-provider"; -import RootNavigator, { - bottomRoutes, - routes -} from "./navigation/navigators/rootnavigator"; import { usePersistentState } from "./utils/hooks"; import { useStore } from "./stores/app-store"; -import { useStore as useNotesStore } from "./stores/note-store"; -import { COLORS } from "./common"; -import { toTitleCase } from "./utils/string"; -import * as Icon from "./components/icons"; import { useStore as useAppStore } from "./stores/app-store"; import { useStore as useUserStore } from "./stores/user-store"; import Animated from "./components/animated"; -import NavItem from "./components/navitem"; +import NavigationMenu from "./components/navigationmenu"; function App() { - const [selectedKey, setSelectedKey] = usePersistentState( - "navSelectedKey", - "home" - ); - const [show, setShow] = usePersistentState("navContainerState", true); - - const isSideMenuOpen = useStore(store => store.isSideMenuOpen); + const [show, setShow] = usePersistentState("isContainerVisible", true); const refreshColors = useStore(store => store.refreshColors); - const setSelectedContext = useNotesStore(store => store.setSelectedContext); const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); const initUser = useUserStore(store => store.init); useEffect(() => { - RootNavigator.navigate(selectedKey); refreshColors(); initUser(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [refreshColors, initUser]); useEffect(() => { if (isFocusModeEnabled) { @@ -48,114 +30,13 @@ function App() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [isFocusModeEnabled]); - const colors = useStore(store => store.colors); return ( - - - - {Object.values(routes).map((item, index) => ( - { - if (selectedKey === item.key) { - setShow(!show); - return; - } - if (item.onClick) { - setSelectedKey(item.key); - return item.onClick(); - } - if (RootNavigator.navigate(item.key)) { - setSelectedKey(item.key); - } - }} - key={item.key} - item={item} - selected={selectedKey === item.key} - /> - ))} - {colors.map(color => { - return ( - { - setSelectedKey(undefined); - setSelectedContext({ - type: "color", - value: color.title - }); - RootNavigator.navigate( - "color", - { - title: toTitleCase(color.title), - context: { colors: [color.title] } - }, - true - ); - }} - key={color.title} - item={{ - color: COLORS[color.title], - title: toTitleCase(color.title), - icon: Icon.Circle, - count: color.noteIds.length - }} - /> - ); - })} - - - {Object.values(bottomRoutes).map((item, index) => ( - { - if (item.onClick) { - await item.onClick(); - if (item.component) setSelectedKey(item.key); - return; - } - if (RootNavigator.navigate(item.key)) { - setSelectedKey(item.key); - } - }} - key={item.key} - item={item} - selected={selectedKey === item.key} - /> - ))} - - - - + setShow(!show)} /> + + - - + /> diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js new file mode 100644 index 000000000..9057bf8b0 --- /dev/null +++ b/apps/web/src/components/navigation-menu/index.js @@ -0,0 +1,109 @@ +import React, { useEffect } from "react"; +import { Box } from "rebass"; +import RootNavigator, { + bottomRoutes, + routes +} from "../../navigation/navigators/rootnavigator"; +import { usePersistentState } from "../../utils/hooks"; +import { useStore } from "../../stores/app-store"; +import { COLORS } from "../../common"; +import { toTitleCase } from "../../utils/string"; +import * as Icon from "../icons"; +import { useStore as useAppStore } from "../../stores/app-store"; +import Animated from "../animated"; +import NavItem from "../navitem"; +import { objectMap } from "../../utils/object"; + +function NavigationMenu(props) { + const { toggleNavigationContainer } = props; + const [selectedRoute, setSelectedRoute] = usePersistentState("route", "home"); + const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); + const colors = useStore(store => store.colors); + const isSideMenuOpen = useStore(store => store.isSideMenuOpen); + + useEffect(() => { + RootNavigator.navigate(selectedRoute); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + {objectMap(routes, (_, item) => ( + { + if (selectedRoute === item.key) toggleNavigationContainer(); + else if (RootNavigator.navigate(item.key)) + setSelectedRoute(item.key); + }} + /> + ))} + {colors.map(color => { + return ( + { + setSelectedRoute(undefined); + RootNavigator.navigate("color", { + title: toTitleCase(color.title), + context: { type: "color", colors: [color.title] } + }); + }} + key={color.title} + item={{ + color: COLORS[color.title], + title: toTitleCase(color.title), + icon: Icon.Circle, + count: color.noteIds.length + }} + /> + ); + })} + + + {Object.values(bottomRoutes).map(item => ( + { + const shouldSelect = + (item.component && item.onClick && (await item.onClick())) || + RootNavigator.navigate(item.key); + if (shouldSelect) setSelectedRoute(item.key); + }} + key={item.key} + item={item} + selected={selectedRoute === item.key} + /> + ))} + + + ); +} +export default NavigationMenu; diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index 15ce57eae..c6894a71f 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -12,7 +12,6 @@ import { createRoute, createNormalRoute, createDeadRoute } from "../routes"; import Navigator from "../index"; import SelectionModeOptions from "../../common/selectionoptions"; import Search from "../../views/Search"; -import { store as noteStore } from "../../stores/note-store"; import { store as userStore } from "../../stores/user-store"; import { store as themeStore } from "../../stores/theme-store"; import { showLogInDialog } from "../../components/dialogs/logindialog"; @@ -29,8 +28,8 @@ export const bottomRoutes = { onClick: async () => { if (!userStore.getState().isLoggedIn) { await showLogInDialog(); - } - RootNavigator.navigate("account"); + return false; + } else return RootNavigator.navigate("account"); } }), ...createRoute("settings", SettingsContainer, { @@ -49,12 +48,7 @@ export const routes = { ...createNormalRoute("favorites", Notes, Icon.StarOutline, { title: "Favorites", options: SelectionModeOptions.FavoritesOptions, - onClick: () => { - noteStore.getState().setSelectedContext({ - type: "favorites" - }); - RootNavigator.navigate("favorites"); - } + context: { type: "favorites" } }), ...createNormalRoute("trash", Trash, Icon.Trash, { title: "Trash", From 9c8a6c881ec645dcf0a73d6e4f20867c7caf8776 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 01:04:59 +0500 Subject: [PATCH 271/394] refactor: signup & login dialogs --- apps/web/src/components/dialogs/dialog.js | 167 +++++++++--------- .../web/src/components/dialogs/logindialog.js | 94 +++------- .../src/components/dialogs/signupdialog.js | 112 +++--------- apps/web/src/components/form/index.js | 14 ++ apps/web/src/components/inputs/email.js | 16 ++ apps/web/src/components/inputs/index.js | 42 +++++ apps/web/src/components/inputs/password.js | 20 +++ .../src/components/theme-provider/index.js | 6 +- apps/web/src/theme/colorscheme/dark.js | 3 +- apps/web/src/theme/colorscheme/light.js | 3 +- apps/web/src/theme/colorscheme/static.js | 6 +- apps/web/src/theme/variants/input.js | 6 +- apps/web/src/theme/variants/text.js | 11 +- apps/web/src/utils/validation.js | 7 + 14 files changed, 254 insertions(+), 253 deletions(-) create mode 100644 apps/web/src/components/form/index.js create mode 100644 apps/web/src/components/inputs/email.js create mode 100644 apps/web/src/components/inputs/index.js create mode 100644 apps/web/src/components/inputs/password.js create mode 100644 apps/web/src/utils/validation.js diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index 70f19103a..f71068163 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -4,98 +4,99 @@ import { Flex, Text, Button as RebassButton } from "rebass"; import ThemeProvider from "../theme-provider"; import * as Icon from "../icons"; import Modal from "react-modal"; -import { useTheme } from "emotion-theming"; function Dialog(props) { - const theme = useTheme(); return ( - - - - - ( + + + - {props.title} - - - {props.content} - - {props.positiveButton && ( - + - {props.positiveButton.loading ? ( - - ) : ( - props.positiveButton.text || "OK" - )} - - )} + {props.title} + + + {props.content} + + {props.positiveButton && ( + + {props.positiveButton.loading ? ( + + ) : ( + props.positiveButton.text || "OK" + )} + + )} - {props.negativeButton && ( - - {props.negativeButton.text || "Cancel"} - - )} + {props.negativeButton && ( + + {props.negativeButton.text || "Cancel"} + + )} + - - + + )} ); } diff --git a/apps/web/src/components/dialogs/logindialog.js b/apps/web/src/components/dialogs/logindialog.js index 54d278c83..61d054b45 100644 --- a/apps/web/src/components/dialogs/logindialog.js +++ b/apps/web/src/components/dialogs/logindialog.js @@ -1,96 +1,48 @@ import React, { useState } from "react"; -import { Flex, Box, Button, Text } from "rebass"; -import { Input } from "@rebass/forms"; +import { Button, Text } from "rebass"; +import Input from "../inputs"; import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; import { showSignUpDialog } from "./signupdialog"; import { useStore } from "../../stores/user-store"; +import PasswordInput from "../inputs/password"; +import Form from "../form"; function LoginDialog(props) { - const [username, setUsername] = useState(); - const [password, setPassword] = useState(); - const [errorMessage, setErrorMessage] = useState(); + const { onClose } = props; + const [error, setError] = useState(); const isLoggingIn = useStore(store => store.isLoggingIn); const login = useStore(store => store.login); + const form = { error: true }; + return ( { - setErrorMessage(); - if (username === "" || username === undefined) { - setErrorMessage("Please enter your username."); - return; - } - - if (password === "" || password === undefined) { - setErrorMessage("Please enter your password."); - return; - } - - login(username, password) - .then(() => { - props.onClose(); - }) - .catch(e => { - setErrorMessage(e.message); - }); + setError(); + if (!form.error) return; + login(form) + .then(onClose) + .catch(e => setError(e.message)); } }} content={ - - { - setUsername(e.target.value); - }} - > - { - setPassword(e.target.value); - }} - > - - - - - - {errorMessage} - - - +
+ + + + {error && {error}} + } /> ); diff --git a/apps/web/src/components/dialogs/signupdialog.js b/apps/web/src/components/dialogs/signupdialog.js index e0ba76fc8..02ad64a7f 100644 --- a/apps/web/src/components/dialogs/signupdialog.js +++ b/apps/web/src/components/dialogs/signupdialog.js @@ -1,107 +1,43 @@ import React, { useState } from "react"; -import { Flex, Box, Text } from "rebass"; -import { Input } from "@rebass/forms"; +import { Text } from "rebass"; +import Input from "../inputs"; import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; -import { db } from "../../common"; +//import { db } from "../../common"; +import EmailInput from "../inputs/email"; +import PasswordInput from "../inputs/password"; +import Form from "../form"; function SignUpDialog(props) { - const [username, setUserName] = useState(); - const [email, setEmail] = useState(); - const [password, setPassword] = useState(); - const [confirmPassword, setConfirmPassword] = useState(); - const [errorMessage, setErrorMessage] = useState(); + const { onClose } = props; + const [error, setError] = useState(); + const form = { error: true }; + return ( { - setErrorMessage(); - - if (username === "" || username === undefined) { - setErrorMessage("Please enter your username."); - return; - } - - if (email === "" || email === undefined) { - setErrorMessage("Please enter your email address."); - return; - } - - if (password !== confirmPassword) { - setErrorMessage("Passwords do not match! Please try again."); - return; - } - - if (password === undefined || password === "") { - setErrorMessage("Please enter password."); - return; - } - - db.user - .signup(username, email, password) - .then(() => { - props.onClose(); - }) - .catch(() => { - setErrorMessage("Couldn't signup. Please try again."); - }); + setError(); + if (form.error) return; + /* db.user + .signup(form) + .then(onClose) + .catch(error => setError(`Couldn't signup. Error: ${error}`)); */ } }} content={ - - { - setUserName(e.target.value); - }} - > - { - setEmail(e.target.value); - }} - > - { - setPassword(e.target.value); - }} - > - { - setConfirmPassword(e.target.value); - }} - > - - - {errorMessage} - - - +
+ + + + {error && {error}} + } /> ); diff --git a/apps/web/src/components/form/index.js b/apps/web/src/components/form/index.js new file mode 100644 index 000000000..cc2df3021 --- /dev/null +++ b/apps/web/src/components/form/index.js @@ -0,0 +1,14 @@ +import React from "react"; +import { Box } from "rebass"; + +function Form(props) { + const { gutter, children, form } = props; + const childrenWithGutter = React.Children.map(children, (child, index) => { + if (!child) return; + const props = { mt: index && gutter, form }; + return React.cloneElement(child, props); + }); + return {childrenWithGutter}; +} + +export default Form; diff --git a/apps/web/src/components/inputs/email.js b/apps/web/src/components/inputs/email.js new file mode 100644 index 000000000..94eee74a6 --- /dev/null +++ b/apps/web/src/components/inputs/email.js @@ -0,0 +1,16 @@ +import React from "react"; +import Input from "./index"; +import { isValidEmail } from "../../utils/validation"; + +function EmailInput() { + return ( + + ); +} +export default EmailInput; diff --git a/apps/web/src/components/inputs/index.js b/apps/web/src/components/inputs/index.js new file mode 100644 index 000000000..ad654150b --- /dev/null +++ b/apps/web/src/components/inputs/index.js @@ -0,0 +1,42 @@ +import React, { useState } from "react"; +import { Input as RebassInput } from "@rebass/forms"; +import { Box, Text } from "rebass"; +import { toTitleCase } from "../../utils/string"; + +function Input(props) { + const { required = true, validate, variant = "input" } = props; + const { name, form, title } = props; + const [themeVariant, setThemeVariant] = useState(variant); + const [error, setError] = useState(props.error); + return ( + + { + const { value } = event.target; + const isValid = !validate || validate(value, form); + if ((!value.trim() && required) || !isValid) { + setThemeVariant("error"); + if (form) form.error = true; + const error = + !isValid || !name + ? props.error + : `${toTitleCase(name)} is required.`; + setError(error); + } else { + setThemeVariant(variant); + if (form) { + form[name] = value; + form.error = false; + } + } + }} + /> + {themeVariant === "error" && {error}} + + ); +} + +export default Input; diff --git a/apps/web/src/components/inputs/password.js b/apps/web/src/components/inputs/password.js new file mode 100644 index 000000000..f68616df0 --- /dev/null +++ b/apps/web/src/components/inputs/password.js @@ -0,0 +1,20 @@ +import React from "react"; +import Input from "./index"; + +function PasswordInput(props) { + const { confirm } = props; + return ( + <> + + {confirm && ( + form.password === password} + /> + )} + + ); +} +export default PasswordInput; diff --git a/apps/web/src/components/theme-provider/index.js b/apps/web/src/components/theme-provider/index.js index e80ba09dc..60034a85e 100644 --- a/apps/web/src/components/theme-provider/index.js +++ b/apps/web/src/components/theme-provider/index.js @@ -12,7 +12,11 @@ function ThemeProvider(props) { injectCss(factory.transform("css")); const theme = factory.construct({ theme: themeType, accent, scale: 1 }); return ( - {props.children} + + {props.children instanceof Function + ? props.children(theme) + : props.children} + ); } export default ThemeProvider; diff --git a/apps/web/src/theme/colorscheme/dark.js b/apps/web/src/theme/colorscheme/dark.js index 565711054..31e1e0d4b 100644 --- a/apps/web/src/theme/colorscheme/dark.js +++ b/apps/web/src/theme/colorscheme/dark.js @@ -5,7 +5,6 @@ class DarkColorSchemeFactory { constructor(accent) { return { primary: accent, - shade: hexToRGB(accent, 0.1), placeholder: hexToRGB("#ffffff", 0.6), background: "#1f1f1f", accent: "#000", @@ -17,7 +16,7 @@ class DarkColorSchemeFactory { overlay: "rgba(255, 255, 255, 0.5)", secondary: "black", icon: "#dbdbdb", - ...new StaticColorSchemeFactory() + ...new StaticColorSchemeFactory(accent) }; } } diff --git a/apps/web/src/theme/colorscheme/light.js b/apps/web/src/theme/colorscheme/light.js index 16ae7f9a4..5ba3a8c8f 100644 --- a/apps/web/src/theme/colorscheme/light.js +++ b/apps/web/src/theme/colorscheme/light.js @@ -15,9 +15,8 @@ class LightColorSchemeFactory { overlay: "rgba(0, 0, 0, 0.1)", secondary: "white", icon: "#3b3b3b", - shade: hexToRGB(accent, 0.1), placeholder: hexToRGB("#000000", 0.6), - ...new StaticColorSchemeFactory() + ...new StaticColorSchemeFactory(accent) }; } } diff --git a/apps/web/src/theme/colorscheme/static.js b/apps/web/src/theme/colorscheme/static.js index 2cd6ee339..fdb50d02c 100644 --- a/apps/web/src/theme/colorscheme/static.js +++ b/apps/web/src/theme/colorscheme/static.js @@ -1,6 +1,10 @@ +import { hexToRGB } from "../../utils/color"; + class StaticColorSchemeFactory { - constructor() { + constructor(accent) { return { + shade: hexToRGB(accent, 0.1), + dimPrimary: hexToRGB(accent, 0.7), fontTertiary: "gray", transparent: "transparent", static: "white", diff --git a/apps/web/src/theme/variants/input.js b/apps/web/src/theme/variants/input.js index 2d7eaf231..b785c8881 100644 --- a/apps/web/src/theme/variants/input.js +++ b/apps/web/src/theme/variants/input.js @@ -1,7 +1,7 @@ class InputFactory { constructor() { return { - default: new Default(), + input: new Default(), error: new Error() }; } @@ -22,7 +22,7 @@ class Default { borderColor: "primary" }, ":hover": { - borderColor: "shade" + borderColor: "dimPrimary" } }; } @@ -31,7 +31,7 @@ class Default { class Error { constructor() { return { - variant: "forms.default", + variant: "forms.input", borderColor: "red", ":focus": { outline: "none", diff --git a/apps/web/src/theme/variants/text.js b/apps/web/src/theme/variants/text.js index d1fc1b3d8..48416d090 100644 --- a/apps/web/src/theme/variants/text.js +++ b/apps/web/src/theme/variants/text.js @@ -4,7 +4,8 @@ class TextFactory { default: new Default(), heading: new Heading(), title: new Title(), - body: new Body() + body: new Body(), + error: new Error() }; } } @@ -41,6 +42,12 @@ class Title { class Body { constructor() { - return { variant: "text.default", fontWeight: "body", fontSize: "body" }; + return { variant: "text.default", fontSize: "body" }; + } +} + +class Error { + constructor() { + return { variant: "text.default", fontSize: "subBody", color: "error" }; } } diff --git a/apps/web/src/utils/validation.js b/apps/web/src/utils/validation.js new file mode 100644 index 000000000..cf8378367 --- /dev/null +++ b/apps/web/src/utils/validation.js @@ -0,0 +1,7 @@ +function isValidEmail(email) { + return /^([a-zA-Z0-9_\-.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9-]+\.)+))([a-zA-Z0-9]{1,30})(\]?)$/.test( + email + ); +} + +export { isValidEmail }; From 632819d3af472940d5bd2fe1585362be90032c07 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 01:25:51 +0500 Subject: [PATCH 272/394] refactor: cleanup base dialog component --- .../components/dialogs/add-notebook-dialog.js | 161 ++++++----- apps/web/src/components/dialogs/confirm.js | 11 +- apps/web/src/components/dialogs/dialog.js | 26 +- .../web/src/components/dialogs/logindialog.js | 21 +- .../components/dialogs/move-note-dialog.js | 272 +++++++++--------- .../src/components/dialogs/password-dialog.js | 53 ++-- .../src/components/dialogs/signupdialog.js | 17 +- .../web/src/components/dialogs/topicdialog.js | 23 +- 8 files changed, 277 insertions(+), 307 deletions(-) diff --git a/apps/web/src/components/dialogs/add-notebook-dialog.js b/apps/web/src/components/dialogs/add-notebook-dialog.js index 216af18ee..6557a0e7f 100644 --- a/apps/web/src/components/dialogs/add-notebook-dialog.js +++ b/apps/web/src/components/dialogs/add-notebook-dialog.js @@ -83,86 +83,6 @@ class AddNotebookDialog extends React.Component { isOpen={props.isOpen} title="Notebook" icon={Icon.Notebook} - content={ - - (this.title = e.target.value)} - placeholder="Enter name" - defaultValue={this.title} - /> - (this.description = e.target.value)} - placeholder="Enter description (optional)" - defaultValue={this.description} - /> - - Topics (optional): - - - {this.state.topics.map((value, index) => ( - - { - this._inputRefs[index] = ref; - if (ref) ref.value = value; // set default value - }} - variant="default" - placeholder="Topic name" - onFocus={e => { - this.lastLength = e.nativeEvent.target.value.length; - if (this.state.focusedInputIndex === index) return; - this.setState({ focusedInputIndex: index }); - }} - onChange={e => { - this.topics[index] = e.target.value; - }} - onKeyUp={e => { - if (e.nativeEvent.key === "Enter") { - this.addTopic(index); - } else if ( - e.nativeEvent.key === "Backspace" && - this.lastLength === 0 && - index > 0 - ) { - this.removeTopic(index); - } - this.lastLength = e.nativeEvent.target.value.length; - }} - /> - this.performActionOnTopic(index)} - > - - {this.state.focusedInputIndex === index ? ( - - ) : ( - - )} - - - - ))} - - - } positiveButton={{ text: props.edit ? "Edit" : "Add", onClick: () => { @@ -175,7 +95,86 @@ class AddNotebookDialog extends React.Component { } }} negativeButton={{ text: "Cancel", onClick: props.close }} - /> + > + + (this.title = e.target.value)} + placeholder="Enter name" + defaultValue={this.title} + /> + (this.description = e.target.value)} + placeholder="Enter description (optional)" + defaultValue={this.description} + /> + + Topics (optional): + + + {this.state.topics.map((value, index) => ( + + { + this._inputRefs[index] = ref; + if (ref) ref.value = value; // set default value + }} + variant="default" + placeholder="Topic name" + onFocus={e => { + this.lastLength = e.nativeEvent.target.value.length; + if (this.state.focusedInputIndex === index) return; + this.setState({ focusedInputIndex: index }); + }} + onChange={e => { + this.topics[index] = e.target.value; + }} + onKeyUp={e => { + if (e.nativeEvent.key === "Enter") { + this.addTopic(index); + } else if ( + e.nativeEvent.key === "Backspace" && + this.lastLength === 0 && + index > 0 + ) { + this.removeTopic(index); + } + this.lastLength = e.nativeEvent.target.value.length; + }} + /> + this.performActionOnTopic(index)} + > + + {this.state.focusedInputIndex === index ? ( + + ) : ( + + )} + + + + ))} + + +
); } } diff --git a/apps/web/src/components/dialogs/confirm.js b/apps/web/src/components/dialogs/confirm.js index 8f77ae039..2b0ff12a9 100644 --- a/apps/web/src/components/dialogs/confirm.js +++ b/apps/web/src/components/dialogs/confirm.js @@ -8,17 +8,16 @@ function Confirm(props) { isOpen={true} title={props.title} icon={props.icon} - content={ - - {props.message} - - } positiveButton={{ text: "Yes", onClick: props.onYes }} negativeButton={{ text: "No", onClick: props.onNo }} - /> + > + + {props.message} + +
); } diff --git a/apps/web/src/components/dialogs/dialog.js b/apps/web/src/components/dialogs/dialog.js index f71068163..ea7dc725a 100644 --- a/apps/web/src/components/dialogs/dialog.js +++ b/apps/web/src/components/dialogs/dialog.js @@ -38,32 +38,14 @@ function Dialog(props) { }} > - + - + {props.title} - {props.content} - + {props.children} + {props.positiveButton && ( setError(e.message)); } }} - content={ -
- - - - {error && {error}} - - } - /> + > +
+ + + + {error && {error}} + +
); } diff --git a/apps/web/src/components/dialogs/move-note-dialog.js b/apps/web/src/components/dialogs/move-note-dialog.js index 9bd48ab62..8aac21752 100644 --- a/apps/web/src/components/dialogs/move-note-dialog.js +++ b/apps/web/src/components/dialogs/move-note-dialog.js @@ -36,144 +36,6 @@ class MoveDialog extends React.Component { ? Icon.Topic : Icon.Notebook } - content={ - - - - { - let item = this.history.pop(); - this.setState({ ...item }); - }} - sx={{ - display: this.history.length ? "block" : "none", - ":hover": { color: "primary" }, - marginRight: 2 - }} - > - - - {title} - - { - if (mode === "write") { - this.setState({ mode: "read" }); - return; - } - this.setState({ mode: "write" }); - setTimeout(() => { - this._inputRef.focus(); - }, 0); - }} - sx={{ - display: type === "notes" ? "none" : "block", - ":hover": { color: "primary" } - }} - > - {mode === "read" ? : } - - - (this._inputRef = ref)} - variant="default" - sx={{ display: mode === "write" ? "block" : "none" }} - my={1} - placeholder={ - type === "notebooks" ? "Notebook name" : "Topic name" - } - onKeyUp={async e => { - if ( - e.nativeEvent.key === "Enter" && - e.target.value.length > 0 - ) { - if (type === "notebooks") { - await db.notebooks.add({ - title: e.target.value - }); - this.setState({ items: db.notebooks.all }); - } else { - await db.notebooks - .notebook(this.selectedNotebook.id) - .topics.add(e.target.value); - this.setState({ - items: db.notebooks.notebook(this.selectedNotebook.id) - .topics.all - }); - } - this._inputRef.value = ""; - this.setState({ mode: "read" }); - } - }} - /> - - {items.length ? ( - items.map(item => { - return ( - { - this.history.push({ - title, - items, - type - }); - if (type === "notebooks") { - this.setState({ - type: "topics", - items: item.topics, - title: item.title - }); - this.selectedNotebook = item; - } else if (type === "topics") { - this.setState({ - type: "notes", - title: `${this.selectedNotebook.title} - ${item.title}`, - items: db.notebooks - .notebook(this.selectedNotebook.id) - .topics.topic(item.title).all - }); - this.selectedTopic = item.title; - } - }} - > - {item.title} - {item.totalNotes !== undefined && ( - - {item.totalNotes + " Notes"} - - )} - - ); - }) - ) : ( - - Nothing here - - )} - - - } positiveButton={{ text: "Move", onClick: async () => { @@ -192,7 +54,139 @@ class MoveDialog extends React.Component { disabled: type !== "notes" }} negativeButton={{ text: "Cancel", onClick: props.onClose }} - /> + > + + + + { + let item = this.history.pop(); + this.setState({ ...item }); + }} + sx={{ + display: this.history.length ? "block" : "none", + ":hover": { color: "primary" }, + marginRight: 2 + }} + > + + + {title} + + { + if (mode === "write") { + this.setState({ mode: "read" }); + return; + } + this.setState({ mode: "write" }); + setTimeout(() => { + this._inputRef.focus(); + }, 0); + }} + sx={{ + display: type === "notes" ? "none" : "block", + ":hover": { color: "primary" } + }} + > + {mode === "read" ? : } + + + (this._inputRef = ref)} + variant="default" + sx={{ display: mode === "write" ? "block" : "none" }} + my={1} + placeholder={type === "notebooks" ? "Notebook name" : "Topic name"} + onKeyUp={async e => { + if (e.nativeEvent.key === "Enter" && e.target.value.length > 0) { + if (type === "notebooks") { + await db.notebooks.add({ + title: e.target.value + }); + this.setState({ items: db.notebooks.all }); + } else { + await db.notebooks + .notebook(this.selectedNotebook.id) + .topics.add(e.target.value); + this.setState({ + items: db.notebooks.notebook(this.selectedNotebook.id) + .topics.all + }); + } + this._inputRef.value = ""; + this.setState({ mode: "read" }); + } + }} + /> + + {items.length ? ( + items.map(item => { + return ( + { + this.history.push({ + title, + items, + type + }); + if (type === "notebooks") { + this.setState({ + type: "topics", + items: item.topics, + title: item.title + }); + this.selectedNotebook = item; + } else if (type === "topics") { + this.setState({ + type: "notes", + title: `${this.selectedNotebook.title} - ${item.title}`, + items: db.notebooks + .notebook(this.selectedNotebook.id) + .topics.topic(item.title).all + }); + this.selectedTopic = item.title; + } + }} + > + {item.title} + {item.totalNotes !== undefined && ( + + {item.totalNotes + " Notes"} + + )} + + ); + }) + ) : ( + + Nothing here + + )} + + +
); } } diff --git a/apps/web/src/components/dialogs/password-dialog.js b/apps/web/src/components/dialogs/password-dialog.js index 246e15750..5c959d6f0 100644 --- a/apps/web/src/components/dialogs/password-dialog.js +++ b/apps/web/src/components/dialogs/password-dialog.js @@ -21,38 +21,37 @@ function PasswordDialog(props) { isOpen={true} title={props.title} icon={props.icon} - content={ - - { - if (e.key === "Enter") { - await submit(); - } else { - setIsWrong(false); - } - }} - /> - {isWrong && ( - - - - Wrong password - - - )} - - } positiveButton={{ text: props.positiveButtonText, onClick: submit }} negativeButton={{ text: "Cancel", onClick: props.onCancel }} - /> + > + + { + if (e.key === "Enter") { + await submit(); + } else { + setIsWrong(false); + } + }} + /> + {isWrong && ( + + + + Wrong password + + + )} + +
); } diff --git a/apps/web/src/components/dialogs/signupdialog.js b/apps/web/src/components/dialogs/signupdialog.js index 02ad64a7f..65e72348f 100644 --- a/apps/web/src/components/dialogs/signupdialog.js +++ b/apps/web/src/components/dialogs/signupdialog.js @@ -31,15 +31,14 @@ function SignUpDialog(props) { .catch(error => setError(`Couldn't signup. Error: ${error}`)); */ } }} - content={ -
- - - - {error && {error}} - - } - /> + > +
+ + + + {error && {error}} + +
); } diff --git a/apps/web/src/components/dialogs/topicdialog.js b/apps/web/src/components/dialogs/topicdialog.js index c65a23f08..5b5e92f71 100644 --- a/apps/web/src/components/dialogs/topicdialog.js +++ b/apps/web/src/components/dialogs/topicdialog.js @@ -13,23 +13,22 @@ function TopicDialog(props) { isOpen={true} title={props.title} icon={props.icon} - content={ - - { - setTopic(e.target.value); - }} - > - - } positiveButton={{ text: "Add", onClick: props.onYes.bind(this, topic) }} negativeButton={{ text: "Cancel", onClick: props.onNo }} - /> + > + + { + setTopic(e.target.value); + }} + > + +
); } From fecded7d38c85bb1bef45c5f6755abcdf3ff9caf Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 02:14:50 +0500 Subject: [PATCH 273/394] ui: fix props not being forwarded to children in form --- apps/web/src/components/dialogs/logindialog.js | 14 ++++++++------ apps/web/src/components/dialogs/signupdialog.js | 16 +++++++++------- apps/web/src/components/dropper/index.js | 12 ++++++++++++ apps/web/src/components/form/index.js | 14 -------------- apps/web/src/components/inputs/email.js | 3 ++- apps/web/src/components/inputs/password.js | 6 ++++-- 6 files changed, 35 insertions(+), 30 deletions(-) create mode 100644 apps/web/src/components/dropper/index.js delete mode 100644 apps/web/src/components/form/index.js diff --git a/apps/web/src/components/dialogs/logindialog.js b/apps/web/src/components/dialogs/logindialog.js index a276c032a..cccff1cf8 100644 --- a/apps/web/src/components/dialogs/logindialog.js +++ b/apps/web/src/components/dialogs/logindialog.js @@ -1,12 +1,12 @@ import React, { useState } from "react"; -import { Button, Text } from "rebass"; +import { Box, Button, Text } from "rebass"; import Input from "../inputs"; import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; import { showSignUpDialog } from "./signupdialog"; import { useStore } from "../../stores/user-store"; import PasswordInput from "../inputs/password"; -import Form from "../form"; +import Dropper from "../dropper"; function LoginDialog(props) { const { onClose } = props; @@ -35,14 +35,16 @@ function LoginDialog(props) { } }} > -
- - + + + + + {error && {error}} - +
); } diff --git a/apps/web/src/components/dialogs/signupdialog.js b/apps/web/src/components/dialogs/signupdialog.js index 65e72348f..aa14ffbcc 100644 --- a/apps/web/src/components/dialogs/signupdialog.js +++ b/apps/web/src/components/dialogs/signupdialog.js @@ -1,12 +1,12 @@ import React, { useState } from "react"; -import { Text } from "rebass"; +import { Text, Box } from "rebass"; import Input from "../inputs"; import * as Icon from "../icons"; import Dialog, { showDialog } from "./dialog"; //import { db } from "../../common"; import EmailInput from "../inputs/email"; import PasswordInput from "../inputs/password"; -import Form from "../form"; +import Dropper from "../dropper"; function SignUpDialog(props) { const { onClose } = props; @@ -32,12 +32,14 @@ function SignUpDialog(props) { } }} > -
- - - + + + + + + {error && {error}} - +
); } diff --git a/apps/web/src/components/dropper/index.js b/apps/web/src/components/dropper/index.js new file mode 100644 index 000000000..d5c884cb4 --- /dev/null +++ b/apps/web/src/components/dropper/index.js @@ -0,0 +1,12 @@ +import React from "react"; + +function Dropper(props) { + const { children } = props; + const fillChildren = React.Children.map(children, (child, index) => { + if (!child) return; + const childProps = { ...props, children: child.props.children }; + return React.cloneElement(child, childProps); + }); + return {fillChildren}; +} +export default Dropper; diff --git a/apps/web/src/components/form/index.js b/apps/web/src/components/form/index.js deleted file mode 100644 index cc2df3021..000000000 --- a/apps/web/src/components/form/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { Box } from "rebass"; - -function Form(props) { - const { gutter, children, form } = props; - const childrenWithGutter = React.Children.map(children, (child, index) => { - if (!child) return; - const props = { mt: index && gutter, form }; - return React.cloneElement(child, props); - }); - return {childrenWithGutter}; -} - -export default Form; diff --git a/apps/web/src/components/inputs/email.js b/apps/web/src/components/inputs/email.js index 94eee74a6..6a67a4eef 100644 --- a/apps/web/src/components/inputs/email.js +++ b/apps/web/src/components/inputs/email.js @@ -2,7 +2,7 @@ import React from "react"; import Input from "./index"; import { isValidEmail } from "../../utils/validation"; -function EmailInput() { +function EmailInput(props) { return ( ); } diff --git a/apps/web/src/components/inputs/password.js b/apps/web/src/components/inputs/password.js index f68616df0..98fba9bdb 100644 --- a/apps/web/src/components/inputs/password.js +++ b/apps/web/src/components/inputs/password.js @@ -1,10 +1,11 @@ import React from "react"; import Input from "./index"; +import Dropper from "../dropper"; function PasswordInput(props) { const { confirm } = props; return ( - <> + {confirm && ( form.password === password} /> )} - + ); } + export default PasswordInput; From acd300337485dd6331516e6c6b5e2aa226c65f55 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 03:00:06 +0500 Subject: [PATCH 274/394] refactor: use flex variants --- apps/web/src/app.js | 5 +- apps/web/src/components/dialogs/dialog.js | 4 +- apps/web/src/components/editor/index.js | 3 +- .../src/components/list-container/index.js | 17 +----- apps/web/src/components/list-item/index.js | 3 +- apps/web/src/components/note/index.js | 2 +- apps/web/src/components/notebook/index.js | 2 +- apps/web/src/components/properties/index.js | 22 +------ apps/web/src/components/search/index.js | 7 +-- .../src/components/theme-provider/index.js | 1 + apps/web/src/theme/variants/flex.js | 44 ++++++++++++++ apps/web/src/theme/variants/index.js | 7 ++- apps/web/src/views/Account.js | 60 +++++++++---------- apps/web/src/views/Notebooks.js | 8 +-- apps/web/src/views/Settings.js | 20 ++----- apps/web/src/views/Tags.js | 4 +- apps/web/src/views/Trash.js | 2 +- 17 files changed, 101 insertions(+), 110 deletions(-) create mode 100644 apps/web/src/theme/variants/flex.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 0a1609a56..69379a377 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -34,8 +34,9 @@ function App() { setShow(!show)} /> - + - + {props.title} {props.children} - + {props.positiveButton && ( { hideProperties(); }} diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index c485f5820..00eb3f711 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -24,26 +24,15 @@ function ListContainer(props) { }); }, [setSearchContext, props.item, props.items, props.type, props.noSearch]); return ( - + {!props.items.length && props.placeholder ? ( - + ) : ( <> {!props.noSearch && } - + {props.children || ( {props.pinned && ( + {note.colors.map((item, index) => ( } info={ - + {new Date(notebook.dateCreated).toDateString().substring(4)} • diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 987a5a38e..5560a4fdc 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -34,25 +34,6 @@ function Properties() { return ( !isFocusModeEnabled && ( <> - showProperties()} - sx={{ - display: arePropertiesVisible ? "none" : "flex", - position: "absolute", - top: "50%", - right: 0, - color: "static", - borderRadius: "100px 0px 0px 100px", - cursor: "pointer", - height: [0, 0, 60] - }} - alignItems="center" - justifyContent="center" - bg="primary" - > - - - {objectMap(COLORS, (label, code) => ( setColor(label)} key={label} > diff --git a/apps/web/src/components/search/index.js b/apps/web/src/components/search/index.js index 96caf55fe..09821e02c 100644 --- a/apps/web/src/components/search/index.js +++ b/apps/web/src/components/search/index.js @@ -11,13 +11,10 @@ function Search(props) { const search = useStore(store => store.search); return ( store.accent); injectCss(factory.transform("css")); const theme = factory.construct({ theme: themeType, accent, scale: 1 }); + console.log("theme", theme); return ( {props.children instanceof Function diff --git a/apps/web/src/theme/variants/flex.js b/apps/web/src/theme/variants/flex.js new file mode 100644 index 000000000..52ae3c185 --- /dev/null +++ b/apps/web/src/theme/variants/flex.js @@ -0,0 +1,44 @@ +class FlexFactory { + constructor(direction) { + const variants = { + Center: new Center(direction), + Fill: new Fill(direction), + CenterFill: new CenterFill(direction) + }; + return Object.fromEntries( + Object.entries(variants).map(([key, value]) => { + return [`${direction}${key}`, value]; + }) + ); + } +} +export default FlexFactory; + +class Center { + constructor(direction) { + return { + justifyContent: "center", + alignItems: "center", + flexDirection: direction + }; + } +} + +class Fill { + constructor(direction) { + return { + flex: "1 1 auto", + flexDirection: direction + }; + } +} + +class CenterFill { + constructor(direction) { + return { + variant: `${direction}Center`, + flex: "1 1 auto", + flexDirection: direction + }; + } +} diff --git a/apps/web/src/theme/variants/index.js b/apps/web/src/theme/variants/index.js index 1b080939b..c7bff13dc 100644 --- a/apps/web/src/theme/variants/index.js +++ b/apps/web/src/theme/variants/index.js @@ -1,13 +1,18 @@ import ButtonFactory from "./button"; import InputFactory from "./input"; import TextFactory from "./text"; +import FlexFactory from "./flex"; class VariantFactory { constructor() { return { buttons: new ButtonFactory(), forms: new InputFactory(), - text: new TextFactory() + text: new TextFactory(), + variants: { + ...new FlexFactory("row"), + ...new FlexFactory("column") + } }; } } diff --git a/apps/web/src/views/Account.js b/apps/web/src/views/Account.js index dfcd6399e..fdbfcbb48 100644 --- a/apps/web/src/views/Account.js +++ b/apps/web/src/views/Account.js @@ -3,38 +3,34 @@ import { Flex, Button, Image, Text } from "rebass"; function Account() { return ( - - - - - {"Alex's Account"} - - - - {"Pro"} - - - - - - - - - + + + + {"Alex's Account"} + + + Pro + + + + + + + ); } diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index 1c7451a31..e64ff7712 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -69,13 +69,7 @@ function NotebooksContainer() { NotebookNavigator.navigate("notebooks"); } }, []); - return ( - - ); + return ; } export { NotebooksContainer, Notebooks }; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index e44420454..29e59c0a5 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -14,9 +14,8 @@ function Settings(props) { const isLoggedIn = useUserStore(store => store.isLoggedIn); return ( - + props.navigator.navigate("account")} > - + {isLoggedIn ? ( <> {user.username} @@ -97,9 +94,8 @@ function Settings(props) { { label: "lightpink", code: "#FABEBE" } ].map(color => ( { setAccent(color.code); }} @@ -185,13 +181,7 @@ function SettingsContainer() { SettingsNavigator.navigate("settings"); } }, []); - return ( - - ); + return ; } const Titles = { diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index 484a88ce8..ca8fb241c 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -59,9 +59,7 @@ function TagsContainer() { TagNavigator.navigate("tags"); } }, []); - return ( - - ); + return ; } export { Tags, TagsContainer }; diff --git a/apps/web/src/views/Trash.js b/apps/web/src/views/Trash.js index 44d8fb621..f52aef88d 100644 --- a/apps/web/src/views/Trash.js +++ b/apps/web/src/views/Trash.js @@ -49,7 +49,7 @@ function Trash() { body={item.headline} index={index} info={ - + • From f54c88c07ab1afecc07718f8ddfc36c5fddc2a82 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 23:25:12 +0500 Subject: [PATCH 275/394] fix: night mode toggle in settings --- apps/web/src/views/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index 29e59c0a5..7d95770c0 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -8,7 +8,7 @@ import { useStore as useThemeStore } from "../stores/theme-store"; function Settings(props) { const theme = useThemeStore(store => store.theme); const accent = useThemeStore(store => store.accent); - const toggleNightMode = useThemeStore(store => store.theme); + const toggleNightMode = useThemeStore(store => store.toggleNightMode); const setAccent = useThemeStore(store => store.theme); const user = useUserStore(store => store.user); const isLoggedIn = useUserStore(store => store.isLoggedIn); From 4833d4652845c6d34b0450001e9eb10930ff8349 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 23:25:43 +0500 Subject: [PATCH 276/394] refactor: improve react-quill logic --- apps/web/src/components/editor/react-quill.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/web/src/components/editor/react-quill.js b/apps/web/src/components/editor/react-quill.js index b1234ec07..f87c57c5f 100644 --- a/apps/web/src/components/editor/react-quill.js +++ b/apps/web/src/components/editor/react-quill.js @@ -35,6 +35,7 @@ const modules = { }; export default class ReactQuill extends Component { + /** @private */ quill; getEditor() { return this.quill.editor; @@ -45,18 +46,11 @@ export default class ReactQuill extends Component { } componentDidUpdate() { - if (this.props.refresh) { - this.quill.setContents(this.props.initialContent); - if ( - !this.props.initialContent || - !this.props.initialContent.ops || - !this.props.initialContent.ops.length - ) - return; + const { initialContent, refresh } = this.props; + if (refresh) { + this.quill.setContents(initialContent); + if (!initialContent.ops || !initialContent.ops.length) return; const text = this.quill.getText(); - if (text[text.length - 1] !== " ") { - this.quill.insertText(text.length - 1, " "); - } this.quill.setSelection(text.length, 0); } } @@ -78,6 +72,7 @@ export default class ReactQuill extends Component { theme: "snow", readOnly }); + if (initialContent) { this.quill.setContents(initialContent); } @@ -102,7 +97,7 @@ export default class ReactQuill extends Component { } textChangeHandler = (delta, oldDelta, source) => { - if (source === "api") return; + if (source !== "user") return; this.props.onChange(this.quill); }; From 2cfc0ae79d0c903c8de925851ba6501ff433f45a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 27 Mar 2020 23:26:09 +0500 Subject: [PATCH 277/394] fix: variant inheritance in flex variants --- apps/web/src/theme/variants/flex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/theme/variants/flex.js b/apps/web/src/theme/variants/flex.js index 52ae3c185..05710aa7f 100644 --- a/apps/web/src/theme/variants/flex.js +++ b/apps/web/src/theme/variants/flex.js @@ -36,7 +36,7 @@ class Fill { class CenterFill { constructor(direction) { return { - variant: `${direction}Center`, + variant: `variants.${direction}Center`, flex: "1 1 auto", flexDirection: direction }; From 2ed4f71f133d01ce5e8eba310e54089fd78e3df0 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 11:44:05 +0500 Subject: [PATCH 278/394] refactor: improve all placeholders --- .../placeholders/favorites-placeholder.js | 1 + apps/web/src/components/placeholders/index.js | 18 ++ .../placeholders/notebooks-placeholder.js | 187 +++++------------- .../placeholders/notesplacholder.js | 158 ++++----------- .../placeholders/tags-placeholder.js | 169 +++++++--------- apps/web/src/components/properties/index.js | 2 +- apps/web/src/utils/random.js | 8 + 7 files changed, 190 insertions(+), 353 deletions(-) create mode 100644 apps/web/src/components/placeholders/index.js create mode 100644 apps/web/src/utils/random.js diff --git a/apps/web/src/components/placeholders/favorites-placeholder.js b/apps/web/src/components/placeholders/favorites-placeholder.js index f88a526aa..a929dc59d 100644 --- a/apps/web/src/components/placeholders/favorites-placeholder.js +++ b/apps/web/src/components/placeholders/favorites-placeholder.js @@ -3,6 +3,7 @@ import React from "react"; import * as Icon from "../icons"; import { Flex, Text } from "rebass"; +//TODO refactor this function FavoritesPlaceholder() { return ( <> diff --git a/apps/web/src/components/placeholders/index.js b/apps/web/src/components/placeholders/index.js new file mode 100644 index 000000000..5865d75ad --- /dev/null +++ b/apps/web/src/components/placeholders/index.js @@ -0,0 +1,18 @@ +import React from "react"; +import { Flex } from "rebass"; + +function Placeholder(props) { + const { items, renderItem } = props; + return ( + <> + + {items.map(renderItem)} + + + ); +} +export default Placeholder; diff --git a/apps/web/src/components/placeholders/notebooks-placeholder.js b/apps/web/src/components/placeholders/notebooks-placeholder.js index bdbd3ffb0..f54ecf905 100644 --- a/apps/web/src/components/placeholders/notebooks-placeholder.js +++ b/apps/web/src/components/placeholders/notebooks-placeholder.js @@ -1,156 +1,59 @@ -import { motion } from "framer-motion"; import React from "react"; import { Box, Flex, Text } from "rebass"; +import Placeholder from "./index"; +import { getRandom } from "../../utils/random"; +const titles = ["Yearbook 2020", "Semester 5", "Final Project", "Ready. Go"]; +const descriptions = [ + "Thoughts & Stuff", + "Ugh. Can't handle it anymore.", + "Have to organize all this :(", + "What the heck!" +]; function NotebooksPlaceholder() { return ( - <> - - ( + - - + - - - My Notebook - - Keep it all organized - + {titles[getRandom(0, 3)]} + + {descriptions[getRandom(0, 3)]} - - - - - - - - - - My Notebook - - Keep it flowing - - - - - - - - - Notebooks you add will appear here. - - + + + + )} + > ); } - export default NotebooksPlaceholder; diff --git a/apps/web/src/components/placeholders/notesplacholder.js b/apps/web/src/components/placeholders/notesplacholder.js index 44eea8ee0..10d97d5d1 100644 --- a/apps/web/src/components/placeholders/notesplacholder.js +++ b/apps/web/src/components/placeholders/notesplacholder.js @@ -1,131 +1,57 @@ -import { motion } from "framer-motion"; import React from "react"; -import { Box, Flex, Text } from "rebass"; -var parameters = { - padding: "4px", - margin: "3px", - width: "170px", - shadow: "primary", - opacity: "0.5" -}; +import { Text, Flex, Box } from "rebass"; +import Placeholder from "./index"; +import * as Icon from "../icons"; +import { getRandom } from "../../utils/random"; + +const colors = ["hover", "primary", "dimPrimary", "shade"]; +const icons = [Icon.Vault, Icon.Pin, Icon.Star]; +const titles = ["Assignment #4", "Git Workflow", "Project Aurora"]; +const words = Array(25).fill(0); function NotesPlaceholder() { return ( - <> - - {[ - { - right: "0px", - bottom: "-50px", - opacity: "0.7", - x: 2, - y: 2, - pos: "absolute" - }, - { - right: null, - bottom: null, - opacity: "0.9", - x: -2, - y: -2, - pos: "relative" - } - ].map(item => ( - { + const Icon = icons[index]; + return ( + - - - + + + + {titles[index]} + + - - - Title - - {[1, 2, 3, 4].map(item => ( + + {words.map(() => ( + bg={colors[getRandom(0, 3)]} + /> ))} - - - - - - - ))} - - - Notes you write appear here. - - + + ); + }} + /> ); } export default NotesPlaceholder; diff --git a/apps/web/src/components/placeholders/tags-placeholder.js b/apps/web/src/components/placeholders/tags-placeholder.js index 08a1f7b53..19928c35b 100644 --- a/apps/web/src/components/placeholders/tags-placeholder.js +++ b/apps/web/src/components/placeholders/tags-placeholder.js @@ -1,102 +1,83 @@ -import { motion } from "framer-motion"; -import React from "react"; -import { Flex, Text } from "rebass"; +import React, { useState, useEffect } from "react"; +import Animated from "../animated"; +import { Text, Flex } from "rebass"; +import { getRandom } from "../../utils/random"; +import Placeholder from "./index"; +import { useAnimation } from "framer-motion"; -const animatedTags = [ - { - delay: 3, - marginTop: "-50px", - size: 14, - text: "presentations", - left: "25px" - }, - { - delay: 12, - marginTop: "20px", - size: 16, - text: "quotesonlife", - left: "90px" - }, - { - delay: 18, - marginTop: "-25px", - size: 18, - text: "workinprogress", - left: "70px" - }, - { - delay: 24, - marginTop: "0px", - size: 14, - text: "todolists", - left: "35px" - }, - { - delay: 30, - marginTop: "40px", - size: 24, - text: "myschoolwork", - left: "50px" - } +const tags = [ + "presentations", + "quotesonlife", + "workinprogress", + "goodlife", + "school", + "lessons", + "essays", + "disasters", + "todolists", + "myschoolwork" ]; function TagsPlaceholder() { return ( - <> - - {animatedTags.map(item => ( - - - - # - - {item.text} - - - ))} - - - - Tags added to notes appear here. - - + ( + + + # + + + + )} + > ); } export default TagsPlaceholder; + +function TagSlider() { + const [tag, setTag] = useState(getRandomTag()); + const controls = useAnimation(); + useEffect(() => { + animate(controls, setTag); + }, [controls]); + return ( + + {tag} + + ); +} + +async function animate(controls, setTag) { + await controls.start({ opacity: 1, y: 0 }); + await controls.start({ + opacity: 0, + y: 50, + transition: { delay: 1, duration: 0.4 } + }); + await controls.start({ + opacity: 0, + y: -50, + transition: { duration: 0 } + }); + setTag(getRandomTag()); + await animate(controls, setTag); +} + +function getRandomTag() { + return tags[getRandom(0, tags.length - 1)]; +} diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 5560a4fdc..06a5bcba1 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -21,7 +21,7 @@ function Properties() { const setTag = useStore(store => store.setTag); const toggleLocked = useStore(store => store.toggleLocked); const hideProperties = useAppStore(store => store.hideProperties); - const showProperties = useAppStore(store => store.showProperties); + //const showProperties = useAppStore(store => store.showProperties); const arePropertiesVisible = useAppStore(store => store.arePropertiesVisible); const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); diff --git a/apps/web/src/utils/random.js b/apps/web/src/utils/random.js new file mode 100644 index 000000000..417c31b10 --- /dev/null +++ b/apps/web/src/utils/random.js @@ -0,0 +1,8 @@ +function getRandom(min, max) { + return Math.round(Math.random() * (max - min) + min); +} + +function getRandomArbitrary(min, max) { + return Math.random() * (max - min) + min; +} +export { getRandom, getRandomArbitrary }; From 39f71df51fbe18248536cbcd057ec6c56d4fd5fe Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 11:50:52 +0500 Subject: [PATCH 279/394] fix: night mode toggle from nav menu --- apps/web/src/components/navigation-menu/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js index 9057bf8b0..56043d6cb 100644 --- a/apps/web/src/components/navigation-menu/index.js +++ b/apps/web/src/components/navigation-menu/index.js @@ -93,8 +93,8 @@ function NavigationMenu(props) { { const shouldSelect = - (item.component && item.onClick && (await item.onClick())) || - RootNavigator.navigate(item.key); + (item.onClick && (await item.onClick())) || + (item.component && RootNavigator.navigate(item.key)); if (shouldSelect) setSelectedRoute(item.key); }} key={item.key} From f0f17c3f76060e9ede25fdde463e114763857408 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 11:57:09 +0500 Subject: [PATCH 280/394] ui: fix css theme variants not loading properly --- apps/web/src/components/search/index.js | 6 ++---- apps/web/src/components/theme-provider/index.js | 4 ++-- apps/web/src/theme/index.js | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/search/index.js b/apps/web/src/components/search/index.js index 09821e02c..85545703a 100644 --- a/apps/web/src/components/search/index.js +++ b/apps/web/src/components/search/index.js @@ -19,7 +19,6 @@ function Search(props) { > diff --git a/apps/web/src/components/theme-provider/index.js b/apps/web/src/components/theme-provider/index.js index bbdbd3e78..3c272d530 100644 --- a/apps/web/src/components/theme-provider/index.js +++ b/apps/web/src/components/theme-provider/index.js @@ -9,9 +9,9 @@ const factory = new ThemeFactory(); function ThemeProvider(props) { const themeType = useStore(store => store.theme); const accent = useStore(store => store.accent); - injectCss(factory.transform("css")); const theme = factory.construct({ theme: themeType, accent, scale: 1 }); - console.log("theme", theme); + injectCss(factory.transform("css", theme)); + return ( {props.children instanceof Function diff --git a/apps/web/src/theme/index.js b/apps/web/src/theme/index.js index 3f1c9ac50..73b4021b2 100644 --- a/apps/web/src/theme/index.js +++ b/apps/web/src/theme/index.js @@ -4,8 +4,8 @@ import FontFactory from "./font"; import TransformerFactory from "./transformer"; class ThemeFactory { - transform(type) { - return new TransformerFactory(type, this); + transform(type, theme) { + return new TransformerFactory(type, theme); } construct(config) { From 0e9fcaf54255f3b77ec47dfbb0a24ccacde35690 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 13:51:18 +0500 Subject: [PATCH 281/394] feat: make zustand store logic ready for classes --- apps/web/src/common/store.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/web/src/common/store.js b/apps/web/src/common/store.js index 3f42c3b69..ab1efc95a 100644 --- a/apps/web/src/common/store.js +++ b/apps/web/src/common/store.js @@ -1,13 +1,25 @@ -import produce from "immer"; +import produce, { immerable } from "immer"; import create from "zustand"; function immer(config) { return function(set, get, api) { - return config(fn => set(produce(fn)), get, api); + const obj = config( + fn => + set(() => + produce(get(), state => { + fn(state); + }) + ), + get, + api + ); + obj[immerable] = true; + return obj; }; } function createStore(store) { + store = store.new ? store.new.bind(store) : store; return create(immer(store)); } From 99424b97586ca39a7a5c7d74fd981fe7bd00a5ec Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 13:52:45 +0500 Subject: [PATCH 282/394] refactor: cleanup appstore and convert it into a class --- apps/web/src/app.js | 6 +- apps/web/src/components/editor/index.js | 7 +- apps/web/src/components/editor/titlebox.js | 10 +- .../src/components/navigation-menu/index.js | 6 +- apps/web/src/components/properties/index.js | 4 +- apps/web/src/stores/app-store.js | 129 ++++-------------- apps/web/src/stores/index.js | 12 ++ 7 files changed, 51 insertions(+), 123 deletions(-) create mode 100644 apps/web/src/stores/index.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index 69379a377..795bbd0fb 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -13,7 +13,7 @@ import NavigationMenu from "./components/navigationmenu"; function App() { const [show, setShow] = usePersistentState("isContainerVisible", true); const refreshColors = useStore(store => store.refreshColors); - const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); + const isFocusMode = useAppStore(store => store.isFocusMode); const initUser = useUserStore(store => store.init); useEffect(() => { @@ -22,13 +22,13 @@ function App() { }, [refreshColors, initUser]); useEffect(() => { - if (isFocusModeEnabled) { + if (isFocusMode) { setShow(false); } else { setShow(true); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isFocusModeEnabled]); + }, [isFocusMode]); return ( diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index dff7d7103..563c2419b 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -30,10 +30,9 @@ function Editor() { const saveSession = useStore(store => store.saveSession); const newSession = useStore(store => store.newSession); const reopenLastSession = useStore(store => store.reopenLastSession); - const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); + const isFocusMode = useAppStore(store => store.isFocusMode); const hideProperties = useAppStore(store => store.hideProperties); const quillRef = useRef(); - useEffect(() => { // move the toolbar outside (easiest way) const toolbar = document.querySelector(".ql-toolbar.ql-snow"); @@ -52,11 +51,11 @@ function Editor() { width={["0%", "0%", "100%"]} initial={{ marginRight: 0 }} animate={{ - marginRight: isFocusModeEnabled ? "25%" : 0 + marginRight: isFocusMode ? "25%" : 0 }} transition={{ duration: 0.3, ease: "easeIn" }} sx={{ - marginLeft: isFocusModeEnabled ? "25%" : 0, + marginLeft: isFocusMode ? "25%" : 0, position: "relative" }} > diff --git a/apps/web/src/components/editor/titlebox.js b/apps/web/src/components/editor/titlebox.js index e9b9b9b73..ea39c1f34 100644 --- a/apps/web/src/components/editor/titlebox.js +++ b/apps/web/src/components/editor/titlebox.js @@ -50,14 +50,8 @@ class TitleBox extends React.Component { alignItems="center" pr={3} onClick={() => { - const { enableFocusMode, disableFocusMode } = appStore.getState(); - if (!this.state.isFocusMode) { - enableFocusMode(); - this.setState({ isFocusMode: true }); - } else { - disableFocusMode(); - this.setState({ isFocusMode: false }); - } + appStore.getState().toggleFocusMode(); + this.setState({ isFocusMode: !this.state.isFocusMode }); }} > {this.state.isFocusMode ? ( diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js index 56043d6cb..7c1c918cd 100644 --- a/apps/web/src/components/navigation-menu/index.js +++ b/apps/web/src/components/navigation-menu/index.js @@ -17,7 +17,7 @@ import { objectMap } from "../../utils/object"; function NavigationMenu(props) { const { toggleNavigationContainer } = props; const [selectedRoute, setSelectedRoute] = usePersistentState("route", "home"); - const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); + const isFocusMode = useAppStore(store => store.isFocusMode); const colors = useStore(store => store.colors); const isSideMenuOpen = useStore(store => store.isSideMenuOpen); @@ -32,8 +32,8 @@ function NavigationMenu(props) { justifyContent="space-between" initial={{ opacity: 1 }} animate={{ - opacity: isFocusModeEnabled ? 0 : 1, - visibility: isFocusModeEnabled ? "hidden" : "visible" + opacity: isFocusMode ? 0 : 1, + visibility: isFocusMode ? "hidden" : "visible" }} transition={{ duration: 0.3, ease: "easeOut" }} sx={{ diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 06a5bcba1..8d5539efb 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -23,7 +23,7 @@ function Properties() { const hideProperties = useAppStore(store => store.hideProperties); //const showProperties = useAppStore(store => store.showProperties); const arePropertiesVisible = useAppStore(store => store.arePropertiesVisible); - const isFocusModeEnabled = useAppStore(store => store.isFocusModeEnabled); + const isFocusMode = useAppStore(store => store.isFocusMode); function changeState(prop, value) { setSession(state => { @@ -32,7 +32,7 @@ function Properties() { } return ( - !isFocusModeEnabled && ( + !isFocusMode && ( <> { - state.isSideMenuOpen = false; - }); - }, - openSideMenu: function() { - set(state => { - state.isSideMenuOpen = true; - }); - }, - refreshColors: function() { - set(state => { - state.colors = db.colors.all; - }); - }, - enableFocusMode: function() { - set(state => { - state.isFocusModeEnabled = true; - }); - }, - disableFocusMode: function() { - set(state => { - state.isFocusModeEnabled = false; - }); - }, - hideProperties: function() { - set(state => { - state.arePropertiesVisible = false; - }); - }, - showProperties: function() { - set(state => { - state.arePropertiesVisible = true; - }); - }, - enterSelectionMode: function() { - set(state => { - state.isSelectionMode = true; - state.shouldSelectAll = false; - }); - }, - exitSelectionMode: function() { - set(state => { - state.isSelectionMode = false; - state.shouldSelectAll = false; - state.selectedItems = []; - }); - }, - selectItem: function(item) { - const index = get().selectedItems.findIndex(v => item.id === v.id); - set(state => { - if (index >= 0) { - state.selectedItems.splice(index, 1); - } else { - state.selectedItems.push(item); - } - }); - if (get().selectedItems.length <= 0) { - get().exitSelectionMode(); - } - }, - setSelectedItems: function(items) { - set(state => { - state.selectedItems = items; - }); - }, - selectAll() { - if (!get().isSelectionMode) return; - set(state => { - state.shouldSelectAll = true; - }); - }, - createVault: function() { - return showPasswordDialog("create_vault", password => - db.vault.create(password) - ); - }, - unlockVault: function() { - return showPasswordDialog("unlock_vault", password => { - return db.vault - .unlock(password) - .then(() => true) - .catch(() => false); - }); - } +class AppStore extends BaseStore { + // default state + isSideMenuOpen = false; + isFocusMode = false; + colors = []; + + refresh = () => { + noteStore.getState().refresh(); + notebookStore.getState().refresh(); + noteStore.getState().refreshSelectedContext(); + trashStore.getState().refresh(); + this.refreshColors(); + }; + + refreshColors = () => { + this.set(state => (state.colors = db.colors.all)); + }; + + toggleFocusMode = () => { + this.set(state => (state.isFocusMode = !state.isFocusMode)); + }; + + toggleSideMenu = () => { + this.set(state => (state.isSideMenuOpen = !state.isSideMenuOpen)); }; } -const [useStore, store] = createStore(appStore); +const [useStore, store] = createStore(AppStore); export { useStore, store }; diff --git a/apps/web/src/stores/index.js b/apps/web/src/stores/index.js new file mode 100644 index 000000000..b94a187e0 --- /dev/null +++ b/apps/web/src/stores/index.js @@ -0,0 +1,12 @@ +class BaseStore { + static new(set, get) { + return new this(set, get); + } + + constructor(set, get) { + this.set = set; + this.get = get; + } +} + +export default BaseStore; From 5fe29fcc00981f746ca1a374dee63434baa0e8c6 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 13:53:13 +0500 Subject: [PATCH 283/394] refactor: move selection logic to its own store --- apps/web/src/common/selectionoptions.js | 6 +-- .../src/components/list-container/index.js | 9 ++-- apps/web/src/components/list-item/index.js | 10 ++--- apps/web/src/navigation/index.js | 9 ++-- apps/web/src/stores/selection-store.js | 45 +++++++++++++++++++ 5 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 apps/web/src/stores/selection-store.js diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 8a42bc5d6..30204401e 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -1,5 +1,5 @@ import * as Icon from "../components/icons"; -import { store as appStore } from "../stores/app-store"; +import { store as selectionStore } from "../stores/app-store"; import { store as notesStore } from "../stores/note-store"; import { store as nbStore } from "../stores/notebook-store"; import { store as editorStore } from "../stores/editor-store"; @@ -12,8 +12,8 @@ function createOption(icon, onClick) { return { icon, onClick: async () => { - await onClick.call(this, appStore.getState()); - appStore.getState().exitSelectionMode(); + await onClick.call(this, selectionStore.getState()); + selectionStore.getState().toggleSelectionMode(false); } }; } diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 00eb3f711..24a1a039f 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -5,16 +5,16 @@ import Search from "../search"; import * as Icon from "../icons"; import { Virtuoso as List } from "react-virtuoso"; import { useStore as useSearchStore } from "../../stores/searchstore"; -import { useStore as useAppStore } from "../../stores/app-store"; +import { useStore as useSelectionStore } from "../../stores/selection-store"; function ListContainer(props) { const setSearchContext = useSearchStore(store => store.setSearchContext); - const shouldSelectAll = useAppStore(store => store.shouldSelectAll); - const setSelectedItems = useAppStore(store => store.setSelectedItems); + const shouldSelectAll = useSelectionStore(store => store.shouldSelectAll); + const setSelectedItems = useSelectionStore(store => store.setSelectedItems); + useEffect(() => { if (shouldSelectAll) setSelectedItems(props.items); }, [shouldSelectAll, setSelectedItems, props.items]); - useEffect(() => { if (props.noSearch) return; setSearchContext({ @@ -23,6 +23,7 @@ function ListContainer(props) { type: props.type }); }, [setSearchContext, props.item, props.items, props.type, props.noSearch]); + return ( {!props.items.length && props.placeholder ? ( diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index f6f7e1f28..66ca47ad1 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -5,8 +5,8 @@ import Dropdown, { DropdownTrigger, DropdownContent } from "../dropdown"; import Menu from "../menu"; import { store as appStore, - useStore as useAppStore -} from "../../stores/app-store"; + useStore as useSelectionStore +} from "../../stores/selection-store"; import useContextMenu from "../../utils/useContextMenu"; function ActionsMenu(props) { @@ -57,11 +57,11 @@ function ListItem(props) { const [parentRef, closeContextMenu] = useContextMenu( `contextMenu${props.index}` ); - const isSelectionMode = useAppStore(store => store.isSelectionMode); - const selectedItems = useAppStore(store => store.selectedItems); + const isSelectionMode = useSelectionStore(store => store.isSelectionMode); + const selectedItems = useSelectionStore(store => store.selectedItems); const isSelected = selectedItems.findIndex(item => props.item.id === item.id) > -1; - const selectItem = useAppStore(store => store.selectItem); + const selectItem = useSelectionStore(store => store.selectItem); const [menuItems, setMenuItems] = useState(props.menuItems); const toggleSelection = useCallback( diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 0ec285ea8..67560dff5 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -5,7 +5,8 @@ import Animated from "../components/animated"; import { AnimatePresence } from "framer-motion"; import * as Icon from "../components/icons"; import ThemeProvider from "../components/theme-provider"; -import { useStore, store } from "../stores/app-store"; +import { useStore } from "../stores/app-store"; +import { store as selectionStore } from "../stores/selection-store"; class Navigator { constructor(root, routes, options = {}) { @@ -47,7 +48,7 @@ class Navigator { return false; } // exit selection mode on navigate - store.getState().exitSelectionMode(); + selectionStore.getState().toggleSelectionMode(false); ReactDOM.render( store.openSideMenu); + const toggleSideMenu = useStore(store => store.toggleSideMenu); const isSelectionMode = useStore(store => store.isSelectionMode); const exitSelectionMode = useStore(store => store.exitSelectionMode); const selectAll = useStore(store => store.selectAll); @@ -123,7 +124,7 @@ function NavigationContainer(props) { )} { + this.set(state => { + const isSelectionMode = + toggleState !== undefined ? toggleState : !state.isSelectionMode; + state.isSelectionMode = isSelectionMode; + state.shouldSelectAll = false; + state.selectedItems = []; + }); + }; + + selectItem = item => { + const index = this.selectedItems.findIndex(v => item.id === v.id); + this.set(state => { + if (index >= 0) { + state.selectedItems.splice(index, 1); + } else { + state.selectedItems.push(item); + } + }); + if (this.selectedItems.length <= 0) { + this.toggleSelectionMode(); + } + }; + + setSelectedItems(items) { + this.set(state => (state.selectedItems = items)); + } + + selectAll() { + if (!this.isSelectionMode) return; + this.set(state => (state.shouldSelectAll = true)); + } +} + +const [useStore, store] = createStore(SelectionStore); + +export { useStore, store }; From 5fae3128615df51b78336fc4a1e63879fea24bca Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 14:32:24 +0500 Subject: [PATCH 284/394] refactor: move vault logic to its own class --- apps/web/src/common/vault.js | 20 ++++++++++++++++++++ apps/web/src/stores/note-store.js | 5 +++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/common/vault.js diff --git a/apps/web/src/common/vault.js b/apps/web/src/common/vault.js new file mode 100644 index 000000000..d090633fc --- /dev/null +++ b/apps/web/src/common/vault.js @@ -0,0 +1,20 @@ +import { db } from "../common"; +import { showPasswordDialog } from "../components/dialogs/passworddialog"; + +class Vault { + static createVault() { + return showPasswordDialog("create_vault", password => + db.vault.create(password) + ); + } + + static unlockVault() { + return showPasswordDialog("unlock_vault", password => { + return db.vault + .unlock(password) + .then(() => true) + .catch(() => false); + }); + } +} +export default Vault; diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index fb1ceffa5..6218b70e0 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -3,6 +3,7 @@ import createStore from "../common/store"; import { store as editorStore } from "./editor-store"; import { store as appStore } from "./app-store"; import { showPasswordDialog } from "../components/dialogs/passworddialog"; +import Vault from "../common/vault"; function noteStore(set, get) { return { @@ -106,9 +107,9 @@ function noteStore(set, get) { .catch(async ({ message }) => { switch (message) { case "ERR_NO_VAULT": - return appStore.getState().createVault(); + return Vault.createVault(); case "ERR_VAULT_LOCKED": - return appStore.getState().unlockVault(); + return Vault.unlockVault(); default: return false; } From fc162be2cf9f0f31bfb26141b73ebe33018308b5 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 15:22:56 +0500 Subject: [PATCH 285/394] refactor: improve notestore code quality --- apps/web/src/common/selectionoptions.js | 2 +- apps/web/src/common/vault.js | 29 +++ apps/web/src/components/note/index.js | 2 +- apps/web/src/stores/app-store.js | 2 +- apps/web/src/stores/editor-store.js | 6 +- apps/web/src/stores/note-store.js | 237 ++++++++++-------------- apps/web/src/views/Notes.js | 13 +- apps/web/src/views/Tags.js | 4 +- apps/web/src/views/Topics.js | 4 +- 9 files changed, 141 insertions(+), 158 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 30204401e..ec5c2e564 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -68,7 +68,7 @@ const UnfavoriteOption = createOption(Icon.Star, function(state) { if (!item.favorite) return; await db.notes.note(item.id).favorite(); }); - notesStore.getState().setSelectedContext({ type: "favorites" }); + notesStore.getState().setContext({ type: "favorites" }); }); const AddToNotebookOption = createOption(Icon.Plus, async function(state) { diff --git a/apps/web/src/common/vault.js b/apps/web/src/common/vault.js index d090633fc..a209e5ee0 100644 --- a/apps/web/src/common/vault.js +++ b/apps/web/src/common/vault.js @@ -16,5 +16,34 @@ class Vault { .catch(() => false); }); } + + static unlockNote(id, done) { + showPasswordDialog("unlock_note", password => { + return db.vault + .remove(id, password) + .then(() => true) + .catch(e => { + if (e.message === "ERR_WRNG_PWD") return false; + else console.error(e); + }); + }).then(res => res && done()); + } + + static lockNote(id, done) { + db.vault + .add(id) + .then(done) + .catch(({ message }) => { + switch (message) { + case "ERR_NO_VAULT": + return Vault.createVault(); + case "ERR_VAULT_LOCKED": + return Vault.unlockVault(); + default: + return false; + } + }) + .then(result => result && this.lock(id)); + } } export default Vault; diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index 3db3ce810..d186da8ea 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -56,7 +56,7 @@ function menuItems(note, context) { .notebook(context.notebook.id) .topics.topic(context.value) .delete(note.id); - await store.getState().setSelectedContext(context); + await store.getState().setContext(context); } }); } diff --git a/apps/web/src/stores/app-store.js b/apps/web/src/stores/app-store.js index 8467ce760..73822e573 100644 --- a/apps/web/src/stores/app-store.js +++ b/apps/web/src/stores/app-store.js @@ -14,7 +14,7 @@ class AppStore extends BaseStore { refresh = () => { noteStore.getState().refresh(); notebookStore.getState().refresh(); - noteStore.getState().refreshSelectedContext(); + noteStore.getState().refreshContext(); trashStore.getState().refresh(); this.refreshColors(); }; diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index da8c2cf24..3109eb9b7 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -138,7 +138,7 @@ function editorStore(set, get) { // we update favorites only if favorite has changed if (!oldSession || oldSession.favorite !== session.favorite) { - notesState.setSelectedContext({ type: "favorites" }); + notesState.setContext({ type: "favorites" }); } }); }, @@ -206,10 +206,10 @@ function updateContext(key, array) { let type = key === "colors" ? "color" : "tag"; // update notes if the selected context (the current view in the navigator) is a tag or color const notesState = noteStore.getState(); - const context = notesState.selectedContext; + const context = notesState.context; if (context.type === type) { const isValue = array.some(value => value === context.value); - if (isValue) noteStore.getState().setSelectedContext(context); + if (isValue) noteStore.getState().setContext(context); } if (type === "tag") { tagStore.getState().refreshTags(); diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 6218b70e0..767c237c6 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -1,149 +1,108 @@ import { db } from "../common/index"; import createStore from "../common/store"; import { store as editorStore } from "./editor-store"; -import { store as appStore } from "./app-store"; -import { showPasswordDialog } from "../components/dialogs/passworddialog"; import Vault from "../common/vault"; +import BaseStore from "."; -function noteStore(set, get) { - return { - notes: { - items: [], - groupCounts: [], - groups: [] - }, - selectedNotes: [], - selectedContext: {}, - selectedNote: 0, - setSelectedNote: function(id) { - set(state => { - state.selectedNote = id; - }); - }, - refresh: function() { - set(state => { - //TODO save group type - state.notes = db.notes.group(undefined, true); - }); - }, - refreshSelectedContext: function() { - const { setSelectedContext, selectedContext } = get(); - if (!selectedContext.type) return; - setSelectedContext(selectedContext); - }, - setSelectedContext: function(context) { - let notes = []; - switch (context.type) { - case "tag": - notes = db.notes.tagged(context.value); - break; - case "color": - notes = db.notes.colored(context.value); - break; - case "topic": - notes = db.notebooks - .notebook(context.notebook.id) - .topics.topic(context.value).all; - break; - case "favorites": - notes = db.notes.favorites; - break; - default: - return; - } - set(state => { - state.selectedContext = context; - state.selectedNotes = notes; - }); - }, - clearSelectedContext: function() { - set(state => { - state.selectedContext = {}; - state.selectedNotes = []; - }); - }, - delete: async function(id) { - await db.notes.delete(id); - const state = get(); - state.setSelectedContext(state.selectedContext); - state.refresh(); - const editorState = editorStore.getState(); - if (editorState.session.id === id) { - editorState.newSession(); - } - }, - pin: async function(note) { - await db.notes.note(note).pin(); - set(state => { - state.notes = db.notes.group(undefined, true); - }); - syncEditor(note.id, "pinned"); - }, - favorite: async function(note) { - await db.notes.note(note).favorite(); - setValue(set, note.id, "favorite", !note.favorite); - }, - unlock: function(noteId) { - showPasswordDialog("unlock_note", password => { - return db.vault - .remove(noteId, password) - .then(() => true) - .catch(e => { - if (e.message === "ERR_WRNG_PWD") return false; - else console.error(e); - }); - }).then(res => { - if (res) { - setValue(set, noteId, "locked", false); - } - }); - }, - lock: function lock(noteId) { - db.vault - .add(noteId) - .then(() => { - setValue(set, noteId, "locked", true); - }) - .catch(async ({ message }) => { - switch (message) { - case "ERR_NO_VAULT": - return Vault.createVault(); - case "ERR_VAULT_LOCKED": - return Vault.unlockVault(); - default: - return false; - } - }) - .then(result => { - if (result === true) { - lock(noteId); - } - }); +class NoteStore extends BaseStore { + notes = { + items: [], + groupCounts: [], + groups: [] + }; + context = undefined; + selectedNote = 0; + + setSelectedNote = id => { + this.set(state => (state.selectedNote = id)); + }; + + refresh = () => { + this.set(state => (state.notes = db.notes.group(undefined, true))); + }; + + refreshContext = () => { + if (!this.context) return; + this.setContext(this.context); + }; + + setContext = context => { + let notes = []; + switch (context.type) { + case "tag": + notes = db.notes.tagged(context.value); + break; + case "color": + notes = db.notes.colored(context.value); + break; + case "topic": + notes = db.notebooks + .notebook(context.notebook.id) + .topics.topic(context.value).all; + break; + case "favorites": + notes = db.notes.favorites; + break; + default: + return; + } + this.set(state => (state.context = { ...context, notes })); + }; + + delete = async id => { + await db.notes.delete(id); + this.refreshContext(); + this.refresh(); + const { session, newSession } = editorStore.getState(); + if (session.id === id) { + newSession(); + } + }; + + pin = async note => { + await db.notes.note(note).pin(); + this.refresh(); + this._syncEditor(note.id, "pinned"); + }; + + favorite = async note => { + await db.notes.note(note).favorite(); + this._setValue(note.id, "favorite", !note.favorite); + }; + + unlock = id => { + Vault.unlockNote(id, () => this._setValue(id, "locked", false)); + }; + + lock = id => { + Vault.lockNote(id, () => this._setValue(id, "locked", true)); + }; + + /** + * @private + */ + _setValue = (noteId, prop, value) => { + this.set(state => { + const { context, notes } = state; + const arr = !context ? notes.items : context.notes; + let index = arr.findIndex(note => note.id === noteId); + if (index < 0) return; + + arr[index][prop] = value; + this._syncEditor(noteId, prop); + }); + }; + + /** + * @private + */ + _syncEditor = (noteId, action) => { + const { session, setSession } = editorStore.getState(); + if (session.id === noteId) { + setSession(state => (state.session[action] = !state.session[action])); } }; } -function syncEditor(noteId, action) { - const editorState = editorStore.getState(); - if (editorState.session.id === noteId) { - editorState.setSession( - state => (state.session[action] = !state.session[action]) - ); - } -} - -function setValue(set, noteId, prop, value) { - set(state => { - const arr = !state.selectedNotes.length - ? state.notes.items - : state.selectedNotes; - let index = arr.findIndex(n => n.id === noteId); - if (index < 0) return; - arr[index][prop] = value; - }); - syncEditor(noteId, prop); -} - -const [useStore, store] = createStore(noteStore); - +const [useStore, store] = createStore(NoteStore); export { useStore, store }; diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 75053d630..616b3e262 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -7,19 +7,14 @@ import { DEFAULT_CONTEXT } from "../common"; function Notes(props) { const newSession = useStore(store => store.newSession); - const selectedNotes = useNotesStore(store => store.selectedNotes); - const selectedContext = useNotesStore(store => store.selectedContext); + const context = useNotesStore(store => store.context); + return ( ( - + )} button={{ content: "Make a new note", diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index ca8fb241c..994c00537 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -18,7 +18,7 @@ function TagNode({ title }) { } function Tags(props) { - const setSelectedContext = useNotesStore(store => store.setSelectedContext); + const setContext = useNotesStore(store => store.setContext); const tags = useStore(store => store.tags); useEffect(() => { store.getState().refreshTags(); @@ -37,7 +37,7 @@ function Tags(props) { title={} info={`${noteIds.length} notes`} onClick={() => { - setSelectedContext({ type: "tag", value: title }); + setContext({ type: "tag", value: title }); props.navigator.navigate("notes", { title: "#" + title, context: { tags: [title] } diff --git a/apps/web/src/views/Topics.js b/apps/web/src/views/Topics.js index 5f4c181d8..e2df01e77 100644 --- a/apps/web/src/views/Topics.js +++ b/apps/web/src/views/Topics.js @@ -7,7 +7,7 @@ import { useStore as useNbStore } from "../stores/notebook-store"; import { showTopicDialog } from "../components/dialogs/topicdialog"; function Topics(props) { - const setSelectedContext = useNoteStore(store => store.setSelectedContext); + const setContext = useNoteStore(store => store.setContext); const setSelectedNotebookTopics = useNbStore( store => store.setSelectedNotebookTopics ); @@ -34,7 +34,7 @@ function Topics(props) { item={item} onClick={() => { let topic = item; - setSelectedContext({ + setContext({ type: "topic", value: topic.title, notebook: props.notebook From 97a3354d92c90c03e1cd200dfae6038b876c065e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 15:50:24 +0500 Subject: [PATCH 286/394] refactor: clean up settings --- apps/web/src/components/accent-item/index.js | 33 +++++ apps/web/src/theme/accents.js | 13 ++ apps/web/src/theme/variants/button.js | 1 + apps/web/src/theme/variants/text.js | 7 + apps/web/src/views/Settings.js | 146 ++++--------------- 5 files changed, 86 insertions(+), 114 deletions(-) create mode 100644 apps/web/src/components/accent-item/index.js create mode 100644 apps/web/src/theme/accents.js diff --git a/apps/web/src/components/accent-item/index.js b/apps/web/src/components/accent-item/index.js new file mode 100644 index 000000000..9b5991773 --- /dev/null +++ b/apps/web/src/components/accent-item/index.js @@ -0,0 +1,33 @@ +import React from "react"; +import { Flex } from "rebass"; +import * as Icon from "../icons"; +import { useStore as useThemeStore } from "../../stores/theme-store"; + +function AccentItem(props) { + const { code, label } = props; + const setAccent = useThemeStore(store => store.setAccent); + const accent = useThemeStore(store => store.accent); + + return ( + setAccent(code)} + key={label} + > + {code === accent && ( + + )} + + + ); +} +export default AccentItem; diff --git a/apps/web/src/theme/accents.js b/apps/web/src/theme/accents.js new file mode 100644 index 000000000..74f75489f --- /dev/null +++ b/apps/web/src/theme/accents.js @@ -0,0 +1,13 @@ +const accents = [ + { label: "red", code: "#ed2d37" }, + { label: "orange", code: "#ec6e05" }, + { label: "yellow", code: "yellow" }, + { label: "green", code: "green" }, + { label: "blue", code: "blue" }, + { label: "purple", code: "purple" }, + { label: "gray", code: "gray" }, + { label: "lightblue", code: "#46F0F0" }, + { label: "indigo", code: "#F032E6" }, + { label: "lightpink", code: "#FABEBE" } +]; +export default accents; diff --git a/apps/web/src/theme/variants/button.js b/apps/web/src/theme/variants/button.js index d3104963d..32a4abf75 100644 --- a/apps/web/src/theme/variants/button.js +++ b/apps/web/src/theme/variants/button.js @@ -62,6 +62,7 @@ class List { variant: "buttons.tertiary", border: "0px solid", borderBottom: "1px solid", + borderBottomColor: "border", borderRadius: 0, p: 2 }; diff --git a/apps/web/src/theme/variants/text.js b/apps/web/src/theme/variants/text.js index 48416d090..06e282850 100644 --- a/apps/web/src/theme/variants/text.js +++ b/apps/web/src/theme/variants/text.js @@ -5,6 +5,7 @@ class TextFactory { heading: new Heading(), title: new Title(), body: new Body(), + subBody: new SubBody(), error: new Error() }; } @@ -46,6 +47,12 @@ class Body { } } +class SubBody { + constructor() { + return { variant: "text.default", fontSize: "subBody" }; + } +} + class Error { constructor() { return { variant: "text.default", fontSize: "subBody", color: "error" }; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index 7d95770c0..67206b55d 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -1,23 +1,21 @@ import React, { useEffect } from "react"; import { Box, Button, Flex, Text } from "rebass"; import * as Icon from "../components/icons"; -import "../app.css"; import { useStore as useUserStore } from "../stores/user-store"; import { useStore as useThemeStore } from "../stores/theme-store"; +import AccentItem from "../components/accent-item"; +import accents from "../theme/accents"; function Settings(props) { const theme = useThemeStore(store => store.theme); - const accent = useThemeStore(store => store.accent); const toggleNightMode = useThemeStore(store => store.toggleNightMode); - const setAccent = useThemeStore(store => store.theme); const user = useUserStore(store => store.user); const isLoggedIn = useUserStore(store => store.isLoggedIn); return ( - + props.navigator.navigate("account")} @@ -26,149 +24,78 @@ function Settings(props) { variant="columnCenter" bg="primary" mr={2} + size={40} sx={{ - width: 40, - height: 40, borderRadius: 80 }} > - + {isLoggedIn ? ( <> {user.username} - {user.email} + {user.email} ) : ( <> - - You are not logged in - - + You are not logged in + Login to sync notes. )} - + Appearance - + - {[ - { label: "red", code: "#ed2d37" }, - { label: "orange", code: "#ec6e05" }, - { label: "yellow", code: "yellow" }, - { label: "green", code: "green" }, - { label: "blue", code: "blue" }, - { label: "purple", code: "purple" }, - { label: "gray", code: "gray" }, - { label: "lightblue", code: "#46F0F0" }, - { label: "indigo", code: "#F032E6" }, - { label: "lightpink", code: "#FABEBE" } - ].map(color => ( - { - setAccent(color.code); - }} - > - {color.code === accent && ( - - )} - - + {accents.map(color => ( + ))} toggleNightMode()} + py={2} > Dark Mode {theme === "dark" ? : } - + Other - - - - + + {["Terms of Service", "Privacy Policy", "About"].map(title => ( + + ))} ); } @@ -184,13 +111,4 @@ function SettingsContainer() { return ; } -const Titles = { - general: "General", - account: "Account", - accent: "Accent Color", - TOS: "Terms of Service", - privacy: "Privacy Policy", - about: "About" -}; - export { Settings, SettingsContainer }; From bfbe6e7adcc109c84fcc7c617792a90d56ba7610 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 28 Mar 2020 23:29:04 +0500 Subject: [PATCH 287/394] ui: minor improvements, font change --- apps/web/src/components/editor/editor.css | 1 + apps/web/src/components/editor/editormenu.js | 36 +++++++++++++++++++ apps/web/src/components/editor/index.js | 34 +++--------------- apps/web/src/components/menu/index.js | 3 +- .../src/components/navigation-menu/index.js | 2 +- apps/web/src/components/navitem/index.js | 2 +- apps/web/src/index.css | 4 +-- apps/web/src/theme/colorscheme/light.js | 2 +- apps/web/src/theme/font/fontsize.js | 4 +-- apps/web/src/theme/font/index.js | 7 ++-- apps/web/src/theme/index.js | 3 +- apps/web/src/theme/transformer/index.js | 2 +- apps/web/src/theme/variants/button.js | 20 +++++++++-- apps/web/src/views/Home.js | 11 +----- 14 files changed, 76 insertions(+), 55 deletions(-) create mode 100644 apps/web/src/components/editor/editormenu.js diff --git a/apps/web/src/components/editor/editor.css b/apps/web/src/components/editor/editor.css index 5b02fa0a6..8c6afed4d 100644 --- a/apps/web/src/components/editor/editor.css +++ b/apps/web/src/components/editor/editor.css @@ -32,6 +32,7 @@ border: none !important; border-top: 1px solid var(--border) !important; padding: 5px !important; + padding-left: 0px !important; } /*Color Overrides*/ diff --git a/apps/web/src/components/editor/editormenu.js b/apps/web/src/components/editor/editormenu.js new file mode 100644 index 000000000..943c74efc --- /dev/null +++ b/apps/web/src/components/editor/editormenu.js @@ -0,0 +1,36 @@ +import React from "react"; +import { useStore } from "../../stores/editor-store"; +import { Flex, Button } from "rebass"; + +function EditorMenu(props) { + const saveSession = useStore(store => store.saveSession); + const newSession = useStore(store => store.newSession); + const { quill } = props; + + return ( + + + + + + + + ); +} +export default EditorMenu; diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index 563c2419b..d401a37a8 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -9,6 +9,7 @@ import { timeConverter } from "../../utils/time"; import { countWords } from "../../utils/string"; import { useStore as useAppStore } from "../../stores/app-store"; import Animated from "../animated"; +import EditorMenu from "./editormenu"; const TextSeperator = () => { return ( @@ -33,6 +34,7 @@ function Editor() { const isFocusMode = useAppStore(store => store.isFocusMode); const hideProperties = useAppStore(store => store.hideProperties); const quillRef = useRef(); + useEffect(() => { // move the toolbar outside (easiest way) const toolbar = document.querySelector(".ql-toolbar.ql-snow"); @@ -63,7 +65,7 @@ function Editor() { variant="columnFill" className="editor" onFocus={() => { - hideProperties(); + //hideProperties(); }} > 0 && <>{isSaving ? "Saving" : "Saved"}} - - newSession()}> - New - - quillRef.current.quill.history.undo()} - > - Undo - - quillRef.current.quill.history.redo()} - > - Redo - - saveSession()}> - Save - - - Export - - + + + )} + + + + {label} + {/* eslint-disable-next-line jsx-a11y/accessible-emoji */} + + ⚫ + + {timeConverter(dateEdited, true)} + + + ); +} +export default DeltaToggle; diff --git a/apps/web/src/components/spliteditor/index.js b/apps/web/src/components/spliteditor/index.js new file mode 100644 index 000000000..f307ab810 --- /dev/null +++ b/apps/web/src/components/spliteditor/index.js @@ -0,0 +1,102 @@ +import React, { useState, useRef } from "react"; +import { Flex, Box, Text } from "rebass"; +import SimpleEditor from "./simpleeditor"; +import DeltaTransformer from "quill/core/delta"; +import DeltaToggle from "./deltatoggle"; +import { useStore } from "../../stores/mergestore"; + +const deltaTransformer = new DeltaTransformer(); + +function SplitEditor(props) { + const conflictedNote = useStore((store) => store.conflictedNote); + const remoteDelta = useStore((store) => store.remoteDelta); + const localDelta = useStore((store) => store.localDelta); + const [localEditor, remoteEditor] = [useRef(), useRef()]; + const [selectedDelta, setSelectedDelta] = useState(-1); + if (!conflictedNote) return null; + return ( + + + setSelectedDelta((s) => (s === 0 ? -1 : 0))} + editors={() => ({ + selectedEditor: remoteEditor.current.quill, + otherEditor: localEditor.current.quill, + })} + /> + + {conflictedNote.title} + + setSelectedDelta((s) => (s === 1 ? -1 : 1))} + editors={() => ({ + selectedEditor: localEditor.current.quill, + otherEditor: remoteEditor.current.quill, + })} + /> + + + + + + + + + + + ); +} + +export default SplitEditor; diff --git a/apps/web/src/components/spliteditor/simpleeditor.js b/apps/web/src/components/spliteditor/simpleeditor.js new file mode 100644 index 000000000..bf7c22a54 --- /dev/null +++ b/apps/web/src/components/spliteditor/simpleeditor.js @@ -0,0 +1,21 @@ +import React, { useEffect } from "react"; +import ReactQuill from "../editor/react-quill"; + +function SimpleEditor(props) { + const { delta, container, id, pref } = props; + useEffect(() => { + const toolbar = document.querySelector(`${container} .ql-toolbar.ql-snow`); + toolbar.remove(); + }, [container]); + return ( + + ); +} +export default SimpleEditor; diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 4483b43fe..57d2430e1 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -38,7 +38,6 @@ class Navigator { this.history.push(this.lastRoute); } this.lastRoute = route; - return this.renderRoute(route); } @@ -95,17 +94,17 @@ class Navigator { _mergeParams(route, params) { return { ...route, - params: { ...route.params, ...params } + params: { ...route.params, ...params }, }; } } export default Navigator; function NavigationContainer(props) { - const toggleSideMenu = useStore(store => store.toggleSideMenu); - const isSelectionMode = useStore(store => store.isSelectionMode); - const exitSelectionMode = useStore(store => store.exitSelectionMode); - const selectAll = useStore(store => store.selectAll); + const toggleSideMenu = useStore((store) => store.toggleSideMenu); + const isSelectionMode = useStore((store) => store.isSelectionMode); + const exitSelectionMode = useStore((store) => store.exitSelectionMode); + const selectAll = useStore((store) => store.selectAll); return ( @@ -128,7 +127,7 @@ function NavigationContainer(props) { height={38} ml={-5} sx={{ - display: ["block", "none", "none"] + display: ["block", "none", "none"], }} > @@ -142,7 +141,7 @@ function NavigationContainer(props) { {props.route.options && isSelectionMode && ( - {props.route.options.map(option => ( + {props.route.options.map((option) => ( {props.route.params.subtitle} diff --git a/apps/web/src/navigation/navigators/editornavigator.js b/apps/web/src/navigation/navigators/editornavigator.js index 37cae80f1..3e4d1652c 100644 --- a/apps/web/src/navigation/navigators/editornavigator.js +++ b/apps/web/src/navigation/navigators/editornavigator.js @@ -1,12 +1,14 @@ import Editor from "../../components/editor"; +import SplitEditor from "../../components/spliteditor"; import Navigator from "../index"; import { createRoute } from "../routes"; const routes = { - ...createRoute("editor", Editor) + ...createRoute("editor", Editor), + ...createRoute("split", SplitEditor), }; const EditorNavigator = new Navigator("EditorNavigator", routes, { - backButtonEnabled: false + defaultRoute: "editor", }); export default EditorNavigator; diff --git a/apps/web/src/navigation/navigators/index.js b/apps/web/src/navigation/navigators/index.js index 060b5601e..387d31100 100644 --- a/apps/web/src/navigation/navigators/index.js +++ b/apps/web/src/navigation/navigators/index.js @@ -2,4 +2,4 @@ export const NotebookNavigator = require("./nbnavigator").default; export const RootNavigator = require("./rootnavigator").default; export const SettingsNavigator = require("./settingnavigator").default; export const TagNavigator = require("./tagnavigator").default; -export const EditorNavigator = require("./editornavigator").default; +//export const EditorNavigator = require("./editornavigator").default; diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index e9a076146..3afdbf530 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -2,14 +2,16 @@ import createStore from "../common/store"; import { store as noteStore } from "./note-store"; import { store as appStore } from "./app-store"; import { store as tagStore } from "./tag-store"; +import { store as mergeStore } from "./mergestore"; import { db } from "../common"; import BaseStore from "."; import Vault from "../common/vault.js"; +import EditorNavigator from "../navigation/navigators/editornavigator"; const SESSION_STATES = { stale: "stale", new: "new" }; const DEFAULT_SESSION = { notebook: undefined, - state: SESSION_STATES.new, + state: undefined, isSaving: false, title: "", timeout: 0, @@ -30,19 +32,27 @@ const DEFAULT_SESSION = { class EditorStore extends BaseStore { session = DEFAULT_SESSION; - openLastSession = () => { + openLastSession = async () => { const id = localStorage.getItem("lastOpenedNote"); - if (!id) return; - this.openSession(db.notes.note(id).data); + if (!id) { + return EditorNavigator.navigate("editor"); + } + await this.openSession(db.notes.note(id).data); }; openSession = async (note) => { clearTimeout(this.get().session.timeout); + if (note.conflicted) { + return await mergeStore.openConflict(note); + } else { + EditorNavigator.navigate("editor"); + } + let content = {}; if (!note.locked) { content = { - text: note.content.text, + text: await db.notes.note(note).text(), delta: await db.notes.note(note).delta(), }; } else { @@ -55,9 +65,9 @@ class EditorStore extends BaseStore { ...DEFAULT_SESSION, ...note, content, + state: SESSION_STATES.new, }; }); - noteStore.setSelectedNote(note.id); }; @@ -87,11 +97,13 @@ class EditorStore extends BaseStore { }; newSession = (context = {}) => { + EditorNavigator.navigate("editor"); clearTimeout(this.get().session.timeout); this.set(function (state) { state.session = { ...DEFAULT_SESSION, ...context, + state: SESSION_STATES.new, }; }); saveLastOpenedNote(); diff --git a/apps/web/src/stores/mergestore.js b/apps/web/src/stores/mergestore.js index ff1f1639d..b9bf6196b 100644 --- a/apps/web/src/stores/mergestore.js +++ b/apps/web/src/stores/mergestore.js @@ -1,6 +1,8 @@ import createStore from "../common/store"; import { db } from "../common"; -import Navigators from "../navigation/navigators"; +import { store as noteStore } from "./note-store"; +import { store as editorStore } from "./editor-store"; +import EditorNavigator from "../navigation/navigators/editornavigator"; import BaseStore from "./index"; class MergeStore extends BaseStore { @@ -8,14 +10,49 @@ class MergeStore extends BaseStore { localDelta; remoteDelta; - openConflict = async note => { + openConflict = async (note) => { + noteStore.setSelectedNote(note.id); const delta = await db.delta.raw(note.content.delta); - this.set(state => { + this.set((state) => { state.conflictedNote = note; state.localDelta = { ...delta, conflicted: false }; state.remoteDelta = delta.conflicted; }); - Navigators.EditorNavigator.navigate("split"); + EditorNavigator.navigate("split"); + }; + + resolveConflict = async (selectedContent, otherContent) => { + const note = this.get().conflictedNote; + selectedContent.delta = { + data: { ops: selectedContent.delta }, + resolved: true, + }; + await db.notes.add({ + id: note.id, + content: selectedContent, + conflicted: false, + }); + if (otherContent) { + otherContent.delta = { + data: { ops: otherContent.delta }, + }; + await db.notes.add({ + ...note, + content: otherContent, + id: undefined, + dateCreated: undefined, + dateEdited: undefined, + title: note.title + " (DUPLICATE)", + }); + } + this.set((state) => { + state.conflictedNote = undefined; + state.localDelta = undefined; + state.remoteDelta = undefined; + }); + noteStore.refresh(); + noteStore.setSelectedNote(note.id); + await editorStore.openSession(note.id); }; } diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index a5dd4da00..88a909f93 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -6910,7 +6910,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@git+ssh://git@github.com:thecodrr/notes-core.git": version "1.2.0" - resolved "git+ssh://git@github.com:thecodrr/notes-core.git#2030036bee3a9e433a4e1716731052d7e10f18b2" + resolved "git+ssh://git@github.com:thecodrr/notes-core.git#069226c64718e4c4eb0e773a7c613db8435b65a8" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" @@ -8374,7 +8374,7 @@ quill-markdown-shortcuts@^0.0.10: quill@^1.3.1, "quill@https://github.com/thecodrr/quill.git#1.3.7": version "1.3.7" - resolved "https://github.com/thecodrr/quill.git#60cfa5a319b49760a0b0c7c4434068e2f117092f" + resolved "https://github.com/thecodrr/quill.git#adbb4f12348764ceca69deaf3c507d8601fdea6e" dependencies: "@mdi/svg" "^5.0.45" clone "^2.1.1" From ed90588101fcac08ab9c44bfefc119f0839d71fa Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sat, 4 Apr 2020 15:20:21 +0500 Subject: [PATCH 308/394] ui: improve focus mode transition --- apps/web/src/components/editor/header.js | 97 +++++++++++++--------- apps/web/src/components/editor/index.js | 6 +- apps/web/src/components/editor/titlebox.js | 67 +++++---------- 3 files changed, 82 insertions(+), 88 deletions(-) diff --git a/apps/web/src/components/editor/header.js b/apps/web/src/components/editor/header.js index 7fa193f1e..c74cd8ac2 100644 --- a/apps/web/src/components/editor/header.js +++ b/apps/web/src/components/editor/header.js @@ -1,6 +1,8 @@ import React from "react"; import "./editor.css"; -import { Text } from "rebass"; +import { Flex, Text } from "rebass"; +import * as Icon from "../icons"; +import { useStore as useAppStore } from "../../stores/app-store"; import TitleBox from "./title-box"; import { useStore, SESSION_STATES } from "../../stores/editor-store"; import { timeConverter } from "../../utils/time"; @@ -22,48 +24,65 @@ function Header() { const isSaving = useStore((store) => store.session.isSaving); const sessionState = useStore((store) => store.session.state); const setSession = useStore((store) => store.setSession); + const isFocusMode = useAppStore((store) => store.isFocusMode); + const toggleFocusMode = useAppStore((store) => store.toggleFocusMode); return ( - <> - - setSession((state) => { - state.session.title = title; - }) - } - sx={{ - paddingTop: 2, - paddingBottom: 0, - }} - /> - + + + setSession((state) => { + state.session.title = title; + }) + } + sx={{ + paddingTop: 2, + paddingBottom: 0, + }} + /> + + {dateEdited > 0 ? ( + <> + {timeConverter(dateEdited)} + + + ) : null} + {text.length > 0 ? ( + <> + {countWords(text) + " words"} + + + ) : null} + {id && id.length > 0 ? <>{isSaving ? "Saving" : "Saved"} : null} + + + { + toggleFocusMode(); }} > - {dateEdited > 0 ? ( - <> - {timeConverter(dateEdited)} - - - ) : null} - {text.length > 0 ? ( - <> - {countWords(text) + " words"} - - - ) : null} - {id && id.length > 0 ? <>{isSaving ? "Saving" : "Saved"} : null} - - + {isFocusMode ? ( + + ) : ( + + )} + + ); } export default Header; diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index be672c7cc..3d0725fac 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -30,14 +30,14 @@ function Editor() { return ( diff --git a/apps/web/src/components/editor/titlebox.js b/apps/web/src/components/editor/titlebox.js index 92dafa139..5ca3a88d0 100644 --- a/apps/web/src/components/editor/titlebox.js +++ b/apps/web/src/components/editor/titlebox.js @@ -1,20 +1,11 @@ import React from "react"; import "./editor.css"; import { Input } from "@rebass/forms"; -import { Flex } from "rebass"; -import * as Icon from "../icons"; -import { store as appStore } from "../../stores/app-store"; class TitleBox extends React.Component { - state = { isFocusMode: false }; - inputRef; - shouldComponentUpdate(nextProps, nextState) { - return ( - nextProps.title !== this.props.title || - nextProps.shouldFocus || - nextState.isFocusMode !== this.state.isFocusMode - ); + shouldComponentUpdate(nextProps) { + return nextProps.title !== this.props.title || nextProps.shouldFocus; } componentDidUpdate() { @@ -26,41 +17,25 @@ class TitleBox extends React.Component { render() { const { title, setTitle, sx } = this.props; return ( - - (this.inputRef = ref)} - maxLength={120} - placeholder="Untitled" - fontFamily="heading" - fontWeight="heading" - fontSize="heading" - display={["none", "flex", "flex"]} - px={2} - sx={{ - borderWidth: 0, - ":focus": { outline: "none" }, - ...sx - }} - value={title} - onChange={e => { - setTitle(e.target.value); - }} - /> - { - appStore.toggleFocusMode(); - this.setState({ isFocusMode: !this.state.isFocusMode }); - }} - > - {this.state.isFocusMode ? ( - - ) : ( - - )} - - + (this.inputRef = ref)} + maxLength={120} + placeholder="Untitled" + fontFamily="heading" + fontWeight="heading" + fontSize="heading" + display={["none", "flex", "flex"]} + px={2} + sx={{ + borderWidth: 0, + ":focus": { outline: "none" }, + ...sx, + }} + value={title} + onChange={(e) => { + setTitle(e.target.value); + }} + /> ); } } From 175b4ebf041dd421d663b7366b8d13d929b31438 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 5 Apr 2020 09:49:12 +0500 Subject: [PATCH 309/394] feat: reenable properties --- apps/web/src/components/editor/header.js | 4 ++ apps/web/src/components/editor/index.js | 2 + apps/web/src/components/icons/index.js | 4 +- apps/web/src/components/properties/index.js | 49 +++++++++++---------- apps/web/src/stores/editor-store.js | 7 +++ 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/apps/web/src/components/editor/header.js b/apps/web/src/components/editor/header.js index c74cd8ac2..0192e091a 100644 --- a/apps/web/src/components/editor/header.js +++ b/apps/web/src/components/editor/header.js @@ -26,6 +26,7 @@ function Header() { const setSession = useStore((store) => store.setSession); const isFocusMode = useAppStore((store) => store.isFocusMode); const toggleFocusMode = useAppStore((store) => store.toggleFocusMode); + const toggleProperties = useStore((store) => store.toggleProperties); return ( @@ -82,6 +83,9 @@ function Header() { )} + toggleProperties()} pr={3}> + + ); } diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index 3d0725fac..822e8143f 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -16,6 +16,8 @@ function Editor() { const setSession = useStore((store) => store.setSession); const saveSession = useStore((store) => store.saveSession); const isFocusMode = useAppStore((store) => store.isFocusMode); + const arePropertiesVisible = useStore((store) => store.arePropertiesVisible); + const toggleProperties = useStore((store) => store.toggleProperties); const quillRef = useRef(); useEffect(() => { diff --git a/apps/web/src/components/icons/index.js b/apps/web/src/components/icons/index.js index eff48011f..108360a3c 100644 --- a/apps/web/src/components/icons/index.js +++ b/apps/web/src/components/icons/index.js @@ -17,7 +17,7 @@ function Icon({ name, size = 24, color = "icon", rotate }) { } function createIcon(name) { - return function(props) { + return function (props) { return ( store.session.pinned); - const favorite = useStore(store => store.session.favorite); - const locked = useStore(store => store.session.locked); - const colors = useStore(store => store.session.colors); - const tags = useStore(store => store.session.tags); + const pinned = useStore((store) => store.session.pinned); + const favorite = useStore((store) => store.session.favorite); + const locked = useStore((store) => store.session.locked); + const colors = useStore((store) => store.session.colors); + const tags = useStore((store) => store.session.tags); - const setSession = useStore(store => store.setSession); - const setColor = useStore(store => store.setColor); - const setTag = useStore(store => store.setTag); - const toggleLocked = useStore(store => store.toggleLocked); - const hideProperties = useAppStore(store => store.hideProperties); + const setSession = useStore((store) => store.setSession); + const setColor = useStore((store) => store.setColor); + const setTag = useStore((store) => store.setTag); + const toggleLocked = useStore((store) => store.toggleLocked); + //const hideProperties = useAppStore((store) => store.hideProperties); //const showProperties = useAppStore(store => store.showProperties); - const arePropertiesVisible = useAppStore(store => store.arePropertiesVisible); - const isFocusMode = useAppStore(store => store.isFocusMode); + const arePropertiesVisible = useStore((store) => store.arePropertiesVisible); + const toggleProperties = useStore((store) => store.toggleProperties); + const isFocusMode = useAppStore((store) => store.isFocusMode); function changeState(prop, value) { - setSession(state => { + setSession((state) => { state.session[prop] = value; }); } @@ -40,7 +41,7 @@ function Properties() { duration: 0.5, bounceDamping: 1, bounceStiffness: 1, - ease: "easeOut" + ease: "easeOut", }} initial={false} style={{ @@ -48,7 +49,7 @@ function Properties() { right: 0, display: "flex", width: 300, - height: "100%" + height: "100%", }} > hideProperties()} + onClick={() => toggleProperties()} sx={{ color: "red", height: 24, - ":active": { color: "darkRed" } + ":active": { color: "darkRed" }, }} > @@ -92,13 +93,13 @@ function Properties() { checked={pinned} icon={Icon.Pin} label="Pin" - onChecked={state => changeState("pinned", state)} + onChecked={(state) => changeState("pinned", state)} /> changeState("favorite", state)} + onChecked={(state) => changeState("favorite", state)} /> { + onKeyUp={(event) => { if ( event.key === "Enter" || event.key === " " || @@ -141,7 +142,7 @@ function Properties() { justifyContent="flex-start" flexWrap="wrap" > - {tags.map(tag => ( + {tags.map((tag) => ( { setTag(tag); @@ -184,7 +185,7 @@ function Properties() { style={{ position: "absolute", cursor: "pointer", - color: "white" + color: "white", }} size={20} /> diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index 3afdbf530..0fd749bd3 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -31,6 +31,7 @@ const DEFAULT_SESSION = { }; class EditorStore extends BaseStore { session = DEFAULT_SESSION; + arePropertiesVisible = false; openLastSession = async () => { const id = localStorage.getItem("lastOpenedNote"); @@ -137,6 +138,12 @@ class EditorStore extends BaseStore { this._setTagOrColor("tag", tag); }; + toggleProperties = () => { + this.set( + (state) => (state.arePropertiesVisible = !state.arePropertiesVisible) + ); + }; + /** * @private internal * @param {Boolean} isLocked From f896ac252df38407ae1dcb61f8b4d5d7d92dfff3 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 5 Apr 2020 11:40:12 +0500 Subject: [PATCH 310/394] ui: overhaul properties --- apps/web/src/components/icons/index.js | 5 +- apps/web/src/components/properties/index.js | 141 ++++++++++---------- apps/web/src/stores/editor-store.js | 21 +-- 3 files changed, 86 insertions(+), 81 deletions(-) diff --git a/apps/web/src/components/icons/index.js b/apps/web/src/components/icons/index.js index 108360a3c..e976c004f 100644 --- a/apps/web/src/components/icons/index.js +++ b/apps/web/src/components/icons/index.js @@ -4,12 +4,13 @@ import * as Icons from "@mdi/js"; import { useTheme } from "emotion-theming"; import Animated from "../animated"; -function Icon({ name, size = 24, color = "icon", rotate }) { +function Icon({ name, size = 24, color = "icon", stroke, rotate }) { const theme = useTheme(); return ( @@ -64,8 +65,8 @@ export const Loading = createIcon(Icons.mdiLoading); export const ChevronLeft = createIcon(Icons.mdiChevronLeft); export const Close = createIcon(Icons.mdiClose); export const Tag = createIcon(Icons.mdiTagOutline); -export const Color = createIcon(Icons.mdiSelectColor); export const Pin = createIcon(Icons.mdiPinOutline); +export const PinFilled = createIcon(Icons.mdiPin); /** Settings Icons */ export const User = createIcon(Icons.mdiAccountOutline); diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 017ef46bd..a78594777 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -1,32 +1,40 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import * as Icon from "../icons"; -import { Box, Flex, Text } from "rebass"; +import { Box, Flex, Text, Button } from "rebass"; import { Input } from "@rebass/forms"; import CheckBox from "../checkbox"; -import { useStore } from "../../stores/editor-store"; +import { useStore, store } from "../../stores/editor-store"; import { COLORS } from "../../common"; import { objectMap } from "../../utils/object"; import { useStore as useAppStore } from "../../stores/app-store"; import { motion } from "framer-motion"; -function Properties() { - const pinned = useStore((store) => store.session.pinned); - const favorite = useStore((store) => store.session.favorite); - const locked = useStore((store) => store.session.locked); - const colors = useStore((store) => store.session.colors); - const tags = useStore((store) => store.session.tags); +const tools = [ + { key: "pinned", icons: { on: Icon.PinFilled, off: Icon.Pin }, label: "Pin" }, + { + key: "favorite", + icons: { on: Icon.Star, off: Icon.StarOutline }, + label: "Favorite", + }, + { key: "locked", icons: { on: Icon.Lock, off: Icon.Unlock }, label: "Lock" }, +]; +function Properties() { + const colors = useStore((store) => store.session.colors); + const toggleLocked = useStore((store) => store.toggleLocked); + const tags = useStore((store) => store.session.tags); const setSession = useStore((store) => store.setSession); const setColor = useStore((store) => store.setColor); const setTag = useStore((store) => store.setTag); - const toggleLocked = useStore((store) => store.toggleLocked); - //const hideProperties = useAppStore((store) => store.hideProperties); - //const showProperties = useAppStore(store => store.showProperties); const arePropertiesVisible = useStore((store) => store.arePropertiesVisible); const toggleProperties = useStore((store) => store.toggleProperties); const isFocusMode = useAppStore((store) => store.isFocusMode); function changeState(prop, value) { + if (prop === "locked") { + toggleLocked(); + return; + } setSession((state) => { state.session[prop] = value; }); @@ -38,7 +46,7 @@ function Properties() { toggleProperties()} > - changeState("pinned", state)} - /> - changeState("favorite", state)} - /> - - - - Move to notebook + + {tools.map((tool) => ( + changeState(tool.key, state)} + /> + ))} - - - Tags: + + + {objectMap(COLORS, (label, code) => ( + setColor(label)} + sx={{ cursor: "pointer" }} + > + + + {label} + + {colors.includes(label) && ( + + )} + + ))} + { @@ -162,41 +174,30 @@ function Properties() { ))} - - - Colors: - - - {objectMap(COLORS, (label, code) => ( - setColor(label)} - key={label} - > - - {colors.includes(label) && ( - - )} - - ))} - ) ); } + +function Toggle(props) { + const { icons, label, onToggle, toggleKey } = props; + const isOn = useStore((store) => store.session[toggleKey]); + return ( + onToggle(!isOn)} + > + {isOn ? : } + + {label} + + + ); +} export default React.memo(Properties); diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index 0fd749bd3..720623169 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -31,7 +31,7 @@ const DEFAULT_SESSION = { }; class EditorStore extends BaseStore { session = DEFAULT_SESSION; - arePropertiesVisible = false; + arePropertiesVisible = true; openLastSession = async () => { const id = localStorage.getItem("lastOpenedNote"); @@ -75,7 +75,7 @@ class EditorStore extends BaseStore { saveSession = (oldSession) => { this.set((state) => (state.session.isSaving = true)); this._saveFn()(this.get().session).then((id) => { - if (!oldSession) { + if (oldSession) { if (oldSession.tags.length !== this.get().session.tags.length) tagStore.refresh(); if (oldSession.colors.length !== this.get().session.colors.length) @@ -111,17 +111,20 @@ class EditorStore extends BaseStore { noteStore.setSelectedNote(0); }; - setSession = (set) => { + setSession = (set, immediate = false) => { clearTimeout(this.get().session.timeout); const oldSession = { ...this.get().session }; this.set((state) => { state.session.state = SESSION_STATES.stale; set(state); - state.session.timeout = setTimeout(() => { - this.session = this.get().session; - this.saveSession(oldSession); - }, 1000); + state.session.timeout = setTimeout( + () => { + this.session = this.get().session; + this.saveSession(oldSession); + }, + immediate ? 0 : 500 + ); }); }; @@ -165,11 +168,11 @@ class EditorStore extends BaseStore { let index = arr.indexOf(value); if (index > -1) { note[`un${key}`](value).then(() => { - this.set((state) => state.session[array].splice(index, 1)); + this.setSession((state) => state.session[array].splice(index, 1), true); }); } else { note[key](value).then(() => { - this.set((state) => state.session[array].push(value)); + this.setSession((state) => state.session[array].push(value), true); }); } } From 37cd0ce2fafb520d90796f3df2b35fd162a9dac6 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 5 Apr 2020 11:54:53 +0500 Subject: [PATCH 311/394] refactor: remove checkbox --- apps/web/src/components/checkbox/index.js | 35 ----------------------- 1 file changed, 35 deletions(-) delete mode 100644 apps/web/src/components/checkbox/index.js diff --git a/apps/web/src/components/checkbox/index.js b/apps/web/src/components/checkbox/index.js deleted file mode 100644 index 67b8ef39f..000000000 --- a/apps/web/src/components/checkbox/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { Flex, Text } from "rebass"; -import { Switch } from "@rebass/forms"; - -function CheckBox(props) { - const [checked, setChecked] = useState(props.checked || false); - useEffect(() => { - setChecked(props.checked); - }, [props.checked]); - return ( - { - if (props.onChecked) { - props.onChecked(!checked); - setChecked(!checked); - } - if (props.onClick) { - props.onClick(); - } - }} - width="full" - alignItems="center" - justifyContent="space-between" - sx={{ cursor: "pointer", marginBottom: 2 }} - > - - - {props.label} - - - - - ); -} -export default CheckBox; From 4c29b24468538bf758d4ccc6d1800b191315781b Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 5 Apr 2020 11:55:04 +0500 Subject: [PATCH 312/394] refactor: cleanup properties --- apps/web/src/components/properties/index.js | 40 ++++---------------- apps/web/src/components/properties/toggle.js | 24 ++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 apps/web/src/components/properties/toggle.js diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index a78594777..dcd29c973 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -1,13 +1,13 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; import * as Icon from "../icons"; import { Box, Flex, Text, Button } from "rebass"; import { Input } from "@rebass/forms"; -import CheckBox from "../checkbox"; -import { useStore, store } from "../../stores/editor-store"; +import { useStore } from "../../stores/editor-store"; import { COLORS } from "../../common"; import { objectMap } from "../../utils/object"; import { useStore as useAppStore } from "../../stores/app-store"; -import { motion } from "framer-motion"; +import Animated from "../animated"; +import Toggle from "./toggle"; const tools = [ { key: "pinned", icons: { on: Icon.PinFilled, off: Icon.Pin }, label: "Pin" }, @@ -43,7 +43,7 @@ function Properties() { return ( !isFocusMode && ( <> - toggleProperties()} > - ))} - - + + ) ); } - -function Toggle(props) { - const { icons, label, onToggle, toggleKey } = props; - const isOn = useStore((store) => store.session[toggleKey]); - return ( - onToggle(!isOn)} - > - {isOn ? : } - - {label} - - - ); -} export default React.memo(Properties); diff --git a/apps/web/src/components/properties/toggle.js b/apps/web/src/components/properties/toggle.js new file mode 100644 index 000000000..4c01c08f4 --- /dev/null +++ b/apps/web/src/components/properties/toggle.js @@ -0,0 +1,24 @@ +import React from "react"; +import { Flex, Text } from "rebass"; +import { useStore } from "../../stores/editor-store"; + +function Toggle(props) { + const { icons, label, onToggle, toggleKey } = props; + const isOn = useStore((store) => store.session[toggleKey]); + return ( + onToggle(!isOn)} + > + {isOn ? : } + + {label} + + + ); +} +export default Toggle; From 4a752806b3f7028b3f6d42c1a96cc707588be240 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 5 Apr 2020 11:55:26 +0500 Subject: [PATCH 313/394] refactor: resolve all warnings --- apps/web/src/components/editor/index.js | 2 -- apps/web/src/components/properties/index.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/web/src/components/editor/index.js b/apps/web/src/components/editor/index.js index 822e8143f..3d0725fac 100644 --- a/apps/web/src/components/editor/index.js +++ b/apps/web/src/components/editor/index.js @@ -16,8 +16,6 @@ function Editor() { const setSession = useStore((store) => store.setSession); const saveSession = useStore((store) => store.saveSession); const isFocusMode = useAppStore((store) => store.isFocusMode); - const arePropertiesVisible = useStore((store) => store.arePropertiesVisible); - const toggleProperties = useStore((store) => store.toggleProperties); const quillRef = useRef(); useEffect(() => { diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index dcd29c973..594761281 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -1,6 +1,6 @@ import React from "react"; import * as Icon from "../icons"; -import { Box, Flex, Text, Button } from "rebass"; +import { Flex, Text, Button } from "rebass"; import { Input } from "@rebass/forms"; import { useStore } from "../../stores/editor-store"; import { COLORS } from "../../common"; From 7f4674359fb3f4c34032c8b296e76a0fdce3c562 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 6 Apr 2020 10:59:52 +0500 Subject: [PATCH 314/394] ui: fixes for dark theme --- apps/web/public/index.html | 7 ++++--- apps/web/src/components/editor/editor.css | 8 ++++++++ apps/web/src/components/editor/react-quill.js | 3 ++- apps/web/src/components/editor/titlebox.js | 1 + apps/web/src/components/properties/index.js | 7 ++++--- apps/web/src/theme/variants/input.js | 15 ++++++++------- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/web/public/index.html b/apps/web/public/index.html index 5c91c0e33..6f9042fd8 100644 --- a/apps/web/public/index.html +++ b/apps/web/public/index.html @@ -9,10 +9,10 @@ name="description" content="Web site created using create-react-app" /> - + /> -->
- React App + Notesnook - A safe place to write From 363a93f46f9348c9a8fd68dca8458bf47ece3eee Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 15 Apr 2020 12:42:56 +0500 Subject: [PATCH 352/394] fix: notes locking/unlocking --- apps/web/src/common/vault.js | 35 +++++++++++++++++-------------- apps/web/src/interfaces/crypto.js | 14 ++++++------- apps/web/yarn.lock | 6 +++--- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/web/src/common/vault.js b/apps/web/src/common/vault.js index 8ca159696..6676f8a6b 100644 --- a/apps/web/src/common/vault.js +++ b/apps/web/src/common/vault.js @@ -3,13 +3,13 @@ import { showPasswordDialog } from "../components/dialogs/passworddialog"; class Vault { static createVault() { - return showPasswordDialog("create_vault", password => + return showPasswordDialog("create_vault", (password) => db.vault.create(password) ); } static unlockVault() { - return showPasswordDialog("unlock_vault", password => { + return showPasswordDialog("unlock_vault", (password) => { return db.vault .unlock(password) .then(() => true) @@ -18,28 +18,31 @@ class Vault { } static unlockNote(id, done) { - showPasswordDialog("unlock_note", password => { + showPasswordDialog("unlock_note", (password) => { return db.vault .remove(id, password) .then(() => true) - .catch(e => { + .catch((e) => { if (e.message === "ERR_WRNG_PWD") return false; else console.error(e); }); - }).then(res => res && done()); + }).then((res) => res && done()); } static openNote(id) { - return showPasswordDialog("unlock_note", password => { - return db.vault - .open(id, password) - .then(note => { - return note.content; - }) - .catch(e => { - if (e.message === "ERR_WRNG_PwD") return; - else console.error(e); - }); + return new Promise((resolve) => { + showPasswordDialog("unlock_note", (password) => { + return db.vault + .open(id, password) + .then((note) => { + resolve(note.content); + return true; + }) + .catch((e) => { + if (e.message === "ERR_WRNG_PwD") return; + else console.error(e); + }); + }); }); } @@ -57,7 +60,7 @@ class Vault { return false; } }) - .then(result => result && Vault.lockNote(id)); + .then((result) => result && Vault.lockNote(id)); } } export default Vault; diff --git a/apps/web/src/interfaces/crypto.js b/apps/web/src/interfaces/crypto.js index ad91aec5f..bfb4ce6e9 100644 --- a/apps/web/src/interfaces/crypto.js +++ b/apps/web/src/interfaces/crypto.js @@ -38,14 +38,14 @@ class Crypto { }; _getKey = async (passwordOrKey) => { - let key, salt; - if (passwordOrKey.password) { - const result = await this.deriveKey(passwordOrKey.password); + let { salt, key, password } = passwordOrKey; + if (password) { + const result = await this.deriveKey(password, salt); key = result.key; salt = result.salt; - } else if (passwordOrKey.key && passwordOrKey.salt) { + } else if (key && salt) { salt = passwordOrKey.salt; - key = this.sodium.from_base64(passwordOrKey.key); + key = this.sodium.from_base64(key); } return { key, salt }; }; @@ -89,9 +89,9 @@ class Crypto { * @param {{password: string}|{key:string, salt: string}} passwordOrKey - password or derived key * @param {{salt: string, iv: string, cipher: string}} cipher - the cipher data */ - decrypt = async (passwordOrKey, { iv, cipher }) => { + decrypt = async (passwordOrKey, { iv, cipher, salt }) => { await this._initialize(); - const { key } = await this._getKey(passwordOrKey); + const { key } = await this._getKey({ salt, ...passwordOrKey }); const plainText = this.sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( undefined, diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 3d8a000ed..4073da950 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7251,9 +7251,9 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -"notes-core@git+ssh://git@github.com:thecodrr/notes-core.git": - version "1.2.0" - resolved "git+ssh://git@github.com:thecodrr/notes-core.git#61249bc5f6452c9490c1be77ba4b1b5489949400" +"notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": + version "1.3.0" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#51209ca353908393e54e810382c940eb158849fc" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From 545d68c9bd72fd112c49c95fab19e81957a19b3a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 15 Apr 2020 13:04:53 +0500 Subject: [PATCH 353/394] fix: use defined errors instead of strings --- apps/web/src/common/vault.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/common/vault.js b/apps/web/src/common/vault.js index 6676f8a6b..4bb7c12ba 100644 --- a/apps/web/src/common/vault.js +++ b/apps/web/src/common/vault.js @@ -23,7 +23,7 @@ class Vault { .remove(id, password) .then(() => true) .catch((e) => { - if (e.message === "ERR_WRNG_PWD") return false; + if (e.message === db.vault.ERRORS.wrongPassword) return false; else console.error(e); }); }).then((res) => res && done()); @@ -39,7 +39,7 @@ class Vault { return true; }) .catch((e) => { - if (e.message === "ERR_WRNG_PwD") return; + if (e.message === db.vault.ERRORS.wrongPassword) return false; else console.error(e); }); }); @@ -52,9 +52,9 @@ class Vault { .then(done) .catch(({ message }) => { switch (message) { - case "ERR_NO_VAULT": + case db.vault.ERRORS.noVault: return Vault.createVault(); - case "ERR_VAULT_LOCKED": + case db.vault.ERRORS.vaultLocked: return Vault.unlockVault(); default: return false; From c7a399e06c4040a3abf92959e83249524b1c329f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 15 Apr 2020 16:30:30 +0500 Subject: [PATCH 354/394] ui: fix lock indicator not updated when locked state changes --- apps/web/src/stores/note-store.js | 2 +- apps/web/yarn.lock | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 8dffe6ced..85380664e 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -69,7 +69,6 @@ class NoteStore extends BaseStore { favorite = async (note) => { await db.notes.note(note).favorite(); - this.refreshContext.defer(); this._setValue(note.id, "favorite", !note.favorite); }; @@ -94,6 +93,7 @@ class NoteStore extends BaseStore { arr[index][prop] = value; this._syncEditor(noteId, prop); }); + this.refresh.defer(); }; /** diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 4073da950..85d674ab4 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -6583,7 +6583,7 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libsodium-wrappers@0.7.6, libsodium-wrappers@^0.7.6: +libsodium-wrappers@0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.6.tgz#baed4c16d4bf9610104875ad8a8e164d259d48fb" integrity sha512-OUO2CWW5bHdLr6hkKLHIKI4raEkZrf3QHkhXsJ1yCh6MZ3JDA7jFD3kCATNquuGSG6MjjPHQIQms0y0gBDzjQg== @@ -7253,11 +7253,10 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": version "1.3.0" - resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#51209ca353908393e54e810382c940eb158849fc" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#9d45d4a13f74ceb5221a38425663a285561307c4" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" - libsodium-wrappers "^0.7.6" qclone "^1.0.4" transfun "^1.0.2" From 110e22ea5756fb5c86aa9ad7762c7194bad3e299 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 15 Apr 2020 16:46:40 +0500 Subject: [PATCH 355/394] crypto: do not check if data is not an object --- apps/web/src/interfaces/crypto.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/web/src/interfaces/crypto.js b/apps/web/src/interfaces/crypto.js index bfb4ce6e9..3b3569ed9 100644 --- a/apps/web/src/interfaces/crypto.js +++ b/apps/web/src/interfaces/crypto.js @@ -58,8 +58,6 @@ class Crypto { encrypt = async (passwordOrKey, data) => { await this._initialize(); - if (typeof data === "object") data = JSON.stringify(data); - const { key, salt } = await this._getKey(passwordOrKey); const nonce = this.sodium.randombytes_buf( From bdfb1eefb85e9852db1d3492517a1627f817b014 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Wed, 15 Apr 2020 22:39:59 +0500 Subject: [PATCH 356/394] ui: update lock indicator when lock/unlock note --- apps/web/src/common/vault.js | 4 ++-- apps/web/src/stores/note-store.js | 10 +++++----- apps/web/yarn.lock | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/web/src/common/vault.js b/apps/web/src/common/vault.js index 4bb7c12ba..08f5f769d 100644 --- a/apps/web/src/common/vault.js +++ b/apps/web/src/common/vault.js @@ -18,7 +18,7 @@ class Vault { } static unlockNote(id, done) { - showPasswordDialog("unlock_note", (password) => { + return showPasswordDialog("unlock_note", (password) => { return db.vault .remove(id, password) .then(() => true) @@ -47,7 +47,7 @@ class Vault { } static lockNote(id, done) { - db.vault + return db.vault .add(id) .then(done) .catch(({ message }) => { diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 85380664e..b4752cc37 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -69,15 +69,16 @@ class NoteStore extends BaseStore { favorite = async (note) => { await db.notes.note(note).favorite(); + this.refreshContext.defer(); this._setValue(note.id, "favorite", !note.favorite); }; - unlock = (id) => { - Vault.unlockNote(id, () => this._setValue(id, "locked", false)); + unlock = async (id) => { + await Vault.unlockNote(id, () => this._setValue(id, "locked", false)); }; - lock = (id) => { - Vault.lockNote(id, () => this._setValue(id, "locked", true)); + lock = async (id) => { + await Vault.lockNote(id, () => this._setValue(id, "locked", true)); }; /** @@ -93,7 +94,6 @@ class NoteStore extends BaseStore { arr[index][prop] = value; this._syncEditor(noteId, prop); }); - this.refresh.defer(); }; /** diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 85d674ab4..a657d9599 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7253,7 +7253,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": version "1.3.0" - resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#9d45d4a13f74ceb5221a38425663a285561307c4" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#9168dd22b467caf873bcdd00171693912d2b672a" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From f5a9aa580cfa0e0d1b10dd19d69afddb4a5d61f5 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 11:32:18 +0500 Subject: [PATCH 357/394] feat: impl logout --- apps/web/src/stores/user-store.js | 4 +++- apps/web/src/views/Account.js | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/web/src/stores/user-store.js b/apps/web/src/stores/user-store.js index db2b7965c..8fc9faa7f 100644 --- a/apps/web/src/stores/user-store.js +++ b/apps/web/src/stores/user-store.js @@ -2,6 +2,7 @@ import createStore from "../common/store"; import { db } from "../common"; import { store as appStore } from "./app-store"; import BaseStore from "./index"; +import RootNavigator from "../navigation/navigators/rootnavigator"; class UserStore extends BaseStore { isLoggedIn = false; @@ -62,12 +63,13 @@ class UserStore extends BaseStore { }; logout = () => { - db.user.logout().then(async () => { + return db.user.logout().then(async () => { this.set((state) => { state.user = undefined; state.isLoggedIn = false; }); await appStore.refresh(); + RootNavigator.navigate("home"); }); }; } diff --git a/apps/web/src/views/Account.js b/apps/web/src/views/Account.js index fdbfcbb48..68aeb4532 100644 --- a/apps/web/src/views/Account.js +++ b/apps/web/src/views/Account.js @@ -1,7 +1,9 @@ import React from "react"; import { Flex, Button, Image, Text } from "rebass"; +import { useStore } from "../stores/user-store"; function Account() { + const logout = useStore((store) => store.logout); return ( Vault - + ); } From 6de64a10300ac5248903bd538021859e03a12452 Mon Sep 17 00:00:00 2001 From: Muhammad Ali Date: Thu, 16 Apr 2020 12:32:33 +0500 Subject: [PATCH 358/394] feat: add colors to note context menu (#125) * added colors to properties * changed to tag colors * color setting changed * cleanup and optimize Co-authored-by: thecodrr --- apps/web/src/components/menu/colors.js | 43 ++++++++++++++++++++++++++ apps/web/src/components/menu/index.js | 12 ++++--- apps/web/src/components/note/index.js | 4 ++- apps/web/src/stores/note-store.js | 18 +++++++++-- apps/web/yarn.lock | 2 +- 5 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/components/menu/colors.js diff --git a/apps/web/src/components/menu/colors.js b/apps/web/src/components/menu/colors.js new file mode 100644 index 000000000..203d92dcf --- /dev/null +++ b/apps/web/src/components/menu/colors.js @@ -0,0 +1,43 @@ +import React from "react"; +import { COLORS } from "../../common"; +import * as Icon from "../icons/index"; +import { objectMap } from "../../utils/object"; +import { useStore } from "../../stores/note-store"; +import { Flex } from "rebass"; + +function Colors(props) { + const { id, colors } = props.data; + const setColor = useStore((store) => store.setColor); + + return ( + + {objectMap(COLORS, (label, code) => ( + setColor(id, label)} + key={label} + > + + {colors.includes(label) && ( + + )} + + ))} + + ); +} +export default Colors; diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index d9cf6e4ab..fe70ea70e 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -31,7 +31,7 @@ function Menu(props) { {props.menuItems.map( (item) => - !item.invisible && ( + !item.visible && ( { @@ -55,9 +55,13 @@ function Menu(props) { }, }} > - - {item.title} - + {item.component ? ( + + ) : ( + + {item.title} + + )} ) )} diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index bb707129d..4f827840a 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -10,10 +10,12 @@ import { store as editorStore } from "../../stores/editor-store"; import { showPasswordDialog } from "../dialogs/passworddialog"; import { db, COLORS } from "../../common"; import { useTheme } from "emotion-theming"; +import Colors from "../menu/colors"; const dropdownRefs = []; function menuItems(note, context) { return [ + { component: Colors }, { title: note.notebook ? "Move" : "Add to", onClick: async () => { @@ -43,7 +45,7 @@ function menuItems(note, context) { }, }, { - invisible: context ? (context.type === "topic" ? false : true) : true, + visible: context ? (context.type === "topic" ? true : false) : false, title: "Remove", onClick: async () => { confirm( diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index b4752cc37..b926e6069 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -81,6 +81,18 @@ class NoteStore extends BaseStore { await Vault.lockNote(id, () => this._setValue(id, "locked", true)); }; + setColor = async (id, color) => { + const note = db.notes.note(id); + if (!note) return; + let index = note.data.colors.indexOf(color); + if (index > -1) { + await note.uncolor(color); + } else { + await note.color(color); + } + this._setValue(id, "colors", db.notes.note(id).data.colors); + }; + /** * @private */ @@ -92,17 +104,17 @@ class NoteStore extends BaseStore { if (index < 0) return; arr[index][prop] = value; - this._syncEditor(noteId, prop); + this._syncEditor(noteId, prop, value); }); }; /** * @private */ - _syncEditor = (noteId, action) => { + _syncEditor = (noteId, action, value) => { const { session, setSession } = editorStore.get(); if (session.id === noteId) { - setSession((state) => (state.session[action] = !state.session[action])); + setSession((state) => (state.session[action] = value)); } }; } diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index a657d9599..97ced67a2 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7253,7 +7253,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": version "1.3.0" - resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#9168dd22b467caf873bcdd00171693912d2b672a" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#f19e76f63dfdf2b9b9914d19ebf139a93dba63c1" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From b745e4402576704a5e4da962efec8a5d25ad6eba Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 12:39:54 +0500 Subject: [PATCH 359/394] feat: remove dropdown --- .../components/dropdown/dropdown-content.js | 24 --- .../components/dropdown/dropdown-trigger.js | 28 --- apps/web/src/components/dropdown/index.js | 163 ------------------ .../components/dropdown/styles/Dropdown.css | 13 -- apps/web/src/components/list-item/index.js | 69 +++----- apps/web/src/components/menu/index.js | 3 +- apps/web/src/components/note/index.js | 2 - apps/web/src/components/notebook/index.js | 16 +- apps/web/src/components/topic/index.js | 6 +- apps/web/src/utils/useContextMenu.js | 7 +- apps/web/src/views/Trash.js | 20 +-- 11 files changed, 47 insertions(+), 304 deletions(-) delete mode 100644 apps/web/src/components/dropdown/dropdown-content.js delete mode 100644 apps/web/src/components/dropdown/dropdown-trigger.js delete mode 100644 apps/web/src/components/dropdown/index.js delete mode 100644 apps/web/src/components/dropdown/styles/Dropdown.css diff --git a/apps/web/src/components/dropdown/dropdown-content.js b/apps/web/src/components/dropdown/dropdown-content.js deleted file mode 100644 index 199c5d9ac..000000000 --- a/apps/web/src/components/dropdown/dropdown-content.js +++ /dev/null @@ -1,24 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; - -class DropdownContent extends Component { - render() { - const { children, className, ...dropdownContentProps } = this.props; - dropdownContentProps.className = `dropdown__content ${className}`; - - return
{children}
; - } -} - -DropdownContent.displayName = "DropdownContent"; - -DropdownContent.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; - -DropdownContent.defaultProps = { - className: "" -}; - -export default DropdownContent; diff --git a/apps/web/src/components/dropdown/dropdown-trigger.js b/apps/web/src/components/dropdown/dropdown-trigger.js deleted file mode 100644 index 394e7f217..000000000 --- a/apps/web/src/components/dropdown/dropdown-trigger.js +++ /dev/null @@ -1,28 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -class DropdownTrigger extends Component { - render () { - const { children, className, ...dropdownTriggerProps } = this.props; - dropdownTriggerProps.className = `dropdown__trigger ${className}`; - - return ( - - {children} - - ); - } -} - -DropdownTrigger.displayName = 'DropdownTrigger'; - -DropdownTrigger.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; - -DropdownTrigger.defaultProps = { - className: '' -}; - -export default DropdownTrigger; diff --git a/apps/web/src/components/dropdown/index.js b/apps/web/src/components/dropdown/index.js deleted file mode 100644 index 3dfecb2fc..000000000 --- a/apps/web/src/components/dropdown/index.js +++ /dev/null @@ -1,163 +0,0 @@ -import React, { cloneElement, Component } from "react"; -import PropTypes from "prop-types"; -import { findDOMNode } from "react-dom"; -import DropdownTrigger from "./dropdown-trigger"; -import DropdownContent from "./dropdown-content"; -import "./styles/Dropdown.css"; - -var lastOpenedDropdown; - -class Dropdown extends Component { - static closeLastOpened() { - if (lastOpenedDropdown) lastOpenedDropdown.hide(); - } - displayName = "Dropdown"; - - componentDidMount() { - window.addEventListener("click", this._onWindowClick); - window.addEventListener("touchstart", this._onWindowClick); - } - - componentWillUnmount() { - window.removeEventListener("click", this._onWindowClick); - window.removeEventListener("touchstart", this._onWindowClick); - } - - constructor(props) { - super(props); - - this.state = { - active: false, - }; - - this._onWindowClick = this._onWindowClick.bind(this); - this._onToggleClick = this._onToggleClick.bind(this); - } - - isActive() { - return typeof this.props.active === "boolean" - ? this.props.active - : this.state.active; - } - - hide() { - this.setState( - { - active: false, - }, - () => { - if (this.props.onHide) { - this.props.onHide(); - } - } - ); - } - - show() { - this.setState( - { - active: true, - }, - () => { - if (this.props.onShow) { - this.props.onShow(); - } - } - ); - } - - _onWindowClick(event) { - const dropdownElement = findDOMNode(this); - if ( - event.target !== dropdownElement && - !dropdownElement.contains(event.target) && - this.isActive() - ) { - this.hide(); - } - } - - _onToggleClick(event) { - event.preventDefault(); - if (lastOpenedDropdown) { - lastOpenedDropdown.hide(); - } - if (this.isActive()) { - this.hide(); - } else { - lastOpenedDropdown = this; - this.show(); - } - - event.stopPropagation(); - } - - cx(classes) { - let names = ""; - for (let c in classes) { - if (classes[c]) names += c; - } - return names; - } - - render() { - const { children, className, disabled, removeElement } = this.props; - // create component classes - const active = this.isActive(); - - const dropdownClasses = this.cx({ - dropdown: true, - "dropdown--active": active, - "dropdown--disabled": disabled, - }); - // stick callback on trigger element - const boundChildren = React.Children.map(children, (child) => { - if (child.type === DropdownTrigger) { - const originalOnClick = child.props.onClick; - child = cloneElement(child, { - ref: "trigger", - onClick: (event) => { - if (!disabled) { - this._onToggleClick(event); - if (originalOnClick) { - originalOnClick.apply(child, arguments); - } - } - }, - }); - } else if (child.type === DropdownContent && removeElement && !active) { - child = null; - } - return child; - }); - const cleanProps = { ...this.props }; - delete cleanProps.active; - delete cleanProps.onShow; - delete cleanProps.onHide; - delete cleanProps.removeElement; - - return ( -
- {boundChildren} -
- ); - } -} - -Dropdown.propTypes = { - disabled: PropTypes.bool, - active: PropTypes.bool, - onHide: PropTypes.func, - onShow: PropTypes.func, - children: PropTypes.node, - className: PropTypes.string, - removeElement: PropTypes.bool, - style: PropTypes.object, -}; - -Dropdown.defaultProps = { - className: "", -}; - -export { DropdownTrigger, DropdownContent }; -export default Dropdown; diff --git a/apps/web/src/components/dropdown/styles/Dropdown.css b/apps/web/src/components/dropdown/styles/Dropdown.css deleted file mode 100644 index 40235cc99..000000000 --- a/apps/web/src/components/dropdown/styles/Dropdown.css +++ /dev/null @@ -1,13 +0,0 @@ -.dropdown { - display: inline-block; -} - -.dropdown__content { - display: none; - position: absolute; -} - -.dropdown--active .dropdown__content { - display: block; -} - diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 2ddf20d32..3823b3e28 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -1,11 +1,10 @@ import React, { useEffect, useState, useCallback } from "react"; import { Flex, Box, Text } from "rebass"; import * as Icon from "../icons"; -import Dropdown, { DropdownTrigger, DropdownContent } from "../dropdown"; import Menu from "../menu"; import { store as appStore, - useStore as useSelectionStore + useStore as useSelectionStore, } from "../../stores/selection-store"; import useContextMenu from "../../utils/useContextMenu"; @@ -32,7 +31,7 @@ function selectMenuItem(isSelected, toggleSelection) { } else { toggleSelection(); } - } + }, }; } @@ -44,7 +43,7 @@ const ItemSelector = ({ isSelected, toggleSelection }) => { marginLeft: 3, marginRight: 1, color: "primary", - cursor: "pointer" + cursor: "pointer", }} onClick={() => toggleSelection()} > @@ -57,11 +56,11 @@ function ListItem(props) { const [parentRef, closeContextMenu] = useContextMenu( `contextMenu${props.index}` ); - const isSelectionMode = useSelectionStore(store => store.isSelectionMode); - const selectedItems = useSelectionStore(store => store.selectedItems); + const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); + const selectedItems = useSelectionStore((store) => store.selectedItems); const isSelected = - selectedItems.findIndex(item => props.item.id === item.id) > -1; - const selectItem = useSelectionStore(store => store.selectItem); + selectedItems.findIndex((item) => props.item.id === item.id) > -1; + const selectItem = useSelectionStore((store) => store.selectItem); const [menuItems, setMenuItems] = useState(props.menuItems); const toggleSelection = useCallback( @@ -79,7 +78,7 @@ function ListItem(props) { if (props.selectable) { setMenuItems([ selectMenuItem(isSelected, toggleSelection), - ...props.menuItems + ...props.menuItems, ]); } }, [props.menuItems, isSelected, props.selectable, toggleSelection]); @@ -94,8 +93,8 @@ function ListItem(props) { borderBottomColor: "border", cursor: "pointer", ":hover": { - borderBottomColor: "primary" - } + borderBottomColor: "primary", + }, }} > {isSelectionMode && ( @@ -114,7 +113,7 @@ function ListItem(props) { position: "relative", marginTop: props.pinned ? 4 : 0, paddingTop: props.pinned ? 0 : 2, - paddingBottom: 2 + paddingBottom: 2, //TODO add onpressed reaction }} @@ -130,7 +129,7 @@ function ListItem(props) { borderRadius: 35, width: 30, height: 30, - boxShadow: "2px 1px 3px #00000066" + boxShadow: "2px 1px 3px #00000066", }} mx={2} > @@ -139,7 +138,7 @@ function ListItem(props) { sx={{ borderRadius: 5, width: 5, - height: 5 + height: 5, }} />
@@ -157,8 +156,8 @@ function ListItem(props) { flex: "1 1 auto", paddingTop: props.pinned ? 4 : 0, ":hover": { - cursor: "pointer" - } + cursor: "pointer", + }, }} > {props.body} @@ -193,32 +192,16 @@ function ListItem(props) { {props.info} - {props.menuItems && props.dropdownRefs && ( - (props.dropdownRefs[props.index] = ref)} - > - closeContextMenu()}> - - - - - - props.dropdownRefs[props.index].hide()} - /> - - + {props.menuItems && ( + )}
- {props.menuItems && props.dropdownRefs && ( + {props.menuItems && ( closeContextMenu()} /> diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index fe70ea70e..0a265c40e 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -1,6 +1,5 @@ import React from "react"; import { Flex, Box, Text } from "rebass"; -import Dropdown from "../dropdown"; function Menu(props) { return ( @@ -36,7 +35,7 @@ function Menu(props) { key={item.title} onClick={(e) => { e.stopPropagation(); - Dropdown.closeLastOpened(); + //Dropdown.closeLastOpened(); if (props.closeMenu) { props.closeMenu(); } diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index 4f827840a..dcd3b0693 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -12,7 +12,6 @@ import { db, COLORS } from "../../common"; import { useTheme } from "emotion-theming"; import Colors from "../menu/colors"; -const dropdownRefs = []; function menuItems(note, context) { return [ { component: Colors }, @@ -156,7 +155,6 @@ function Note(props) { pinned={props.pinnable && note.pinned} menuData={note} menuItems={menuItems(note, props.context)} - dropdownRefs={dropdownRefs} /> ); } diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index 0494ab1f0..bd65701e4 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -4,22 +4,21 @@ import ListItem from "../list-item"; import { store } from "../../stores/notebook-store"; import { showEditNoteDialog } from "../dialogs/addnotebookdialog"; -const dropdownRefs = []; function menuItems(notebook, index) { return [ { title: notebook.pinned ? "Unpin" : "Pin", - onClick: () => store.pin(notebook, index) + onClick: () => store.pin(notebook, index), }, { title: "Edit", - onClick: () => showEditNoteDialog(notebook) + onClick: () => showEditNoteDialog(notebook), }, { title: "Delete", color: "red", - onClick: () => store.delete(notebook.id, index) - } + onClick: () => store.delete(notebook.id, index), + }, ]; } @@ -46,9 +45,9 @@ class Notebook extends React.Component { body={notebook.description} subBody={ - {notebook.topics.slice(1, 4).map(topic => ( + {notebook.topics.slice(1, 4).map((topic) => ( { + onClick={(e) => { onTopicClick(notebook, topic); e.stopPropagation(); }} @@ -60,7 +59,7 @@ class Notebook extends React.Component { borderRadius: "default", color: "static", paddingTop: 0.4, - paddingBottom: 0.4 + paddingBottom: 0.4, }} > @@ -80,7 +79,6 @@ class Notebook extends React.Component { } pinned={notebook.pinned} - dropdownRefs={dropdownRefs} index={index} menuData={notebook} menuItems={menuItems(notebook, index)} diff --git a/apps/web/src/components/topic/index.js b/apps/web/src/components/topic/index.js index 7aab0184f..9ff7a8fd9 100644 --- a/apps/web/src/components/topic/index.js +++ b/apps/web/src/components/topic/index.js @@ -1,12 +1,11 @@ import React from "react"; import ListItem from "../list-item"; -const dropdownRefs = []; const menuItems = [ { title: "Delete", - color: "red" - } + color: "red", + }, ]; function Topic({ item, index, onClick }) { @@ -19,7 +18,6 @@ function Topic({ item, index, onClick }) { title={topic.title} info={`${topic.totalNotes} Notes`} index={index} - dropdownRefs={dropdownRefs} menuData={topic} menuItems={menuItems} /> diff --git a/apps/web/src/utils/useContextMenu.js b/apps/web/src/utils/useContextMenu.js index be4521008..a91081b93 100644 --- a/apps/web/src/utils/useContextMenu.js +++ b/apps/web/src/utils/useContextMenu.js @@ -1,6 +1,4 @@ import { useEffect, useRef } from "react"; -import Dropdown from "../components/dropdown"; - var oldOpenedMenu; function isMouseInside(e, element) { @@ -13,7 +11,6 @@ function contextMenuHandler(event, ref, menuId) { isMouseInside(event, ref.current) && !isMouseInside(event, oldOpenedMenu) ) { - Dropdown.closeLastOpened(); dismissMenu(oldOpenedMenu); event.preventDefault(); @@ -41,7 +38,7 @@ function useContextMenu(menuId) { const ref = useRef(); useEffect(() => { const parent = ref.current; - const handler = e => contextMenuHandler(e, ref, menuId); + const handler = (e) => contextMenuHandler(e, ref, menuId); parent.addEventListener("contextmenu", handler); window.onkeydown = onKeyDown; window.onclick = onClick; @@ -72,7 +69,7 @@ function getPosition(e) { return { x: posx - 50, - y: posy - 100 + y: posy - 100, }; } diff --git a/apps/web/src/views/Trash.js b/apps/web/src/views/Trash.js index 3ea63170f..dd18ba0ed 100644 --- a/apps/web/src/views/Trash.js +++ b/apps/web/src/views/Trash.js @@ -8,12 +8,11 @@ import { confirm } from "../components/dialogs/confirm"; import { useStore, store } from "../stores/trash-store"; import { toTitleCase } from "../utils/string"; -const dropdownRefs = []; function menuItems(item, index) { return [ { title: "Restore", - onClick: () => store.restore(item.id, index) + onClick: () => store.restore(item.id, index), }, { title: "Delete", @@ -23,20 +22,20 @@ function menuItems(item, index) { Icon.Trash, "Delete", `Are you sure you want to permanently delete this item?` - ).then(async res => { + ).then(async (res) => { if (res) { await store.delete(item.id, index); } }); - } - } + }, + }, ]; } function Trash() { useEffect(() => store.refresh(), []); - const items = useStore(store => store.trash); - const clearTrash = useStore(store => store.clear); + const items = useStore((store) => store.trash); + const clearTrash = useStore((store) => store.clear); return ( )} button={{ content: "Clear Trash", icon: Icon.Trash, - onClick: function() { + onClick: function () { confirm( Icon.Trash, "Clear", `This action is irreversible. Are you sure you want to proceed?s` - ).then(async res => { + ).then(async (res) => { if (res) { await clearTrash(); } }); - } + }, }} /> ); From 5685a17353b380c6c7fe020f633451acd3fe59ed Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 13:26:08 +0500 Subject: [PATCH 360/394] fix: context menu not opening from menu button --- apps/web/src/components/icons/index.js | 1 + apps/web/src/components/list-item/index.js | 49 ++++++++++------------ apps/web/src/utils/useContextMenu.js | 34 ++++++++++----- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/apps/web/src/components/icons/index.js b/apps/web/src/components/icons/index.js index e976c004f..58e619f5e 100644 --- a/apps/web/src/components/icons/index.js +++ b/apps/web/src/components/icons/index.js @@ -26,6 +26,7 @@ function createIcon(name) { whileHover={{ scale: 1.1 }} transition={{ duration: 0.3, ease: "easeOut" }} animate={props.animation} + onClick={props.onClick} > diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 3823b3e28..2c0e55749 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -1,4 +1,5 @@ import React, { useEffect, useState, useCallback } from "react"; +import ReactDOM from "react-dom"; import { Flex, Box, Text } from "rebass"; import * as Icon from "../icons"; import Menu from "../menu"; @@ -8,18 +9,6 @@ import { } from "../../stores/selection-store"; import useContextMenu from "../../utils/useContextMenu"; -function ActionsMenu(props) { - return ( - - ); -} - function selectMenuItem(isSelected, toggleSelection) { return { title: isSelected ? "Unselect" : "Select", @@ -53,9 +42,8 @@ const ItemSelector = ({ isSelected, toggleSelection }) => { }; function ListItem(props) { - const [parentRef, closeContextMenu] = useContextMenu( - `contextMenu${props.index}` - ); + const menuId = `contextMenu${props.index}`; + const [parentRef, closeMenu, openMenu] = useContextMenu(menuId); const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); const selectedItems = useSelectionStore((store) => store.selectedItems); const isSelected = @@ -198,22 +186,27 @@ function ListItem(props) { strokeWidth={2} color="icon" style={{ marginRight: -5 }} + onClick={(e) => { + openMenu(e.nativeEvent, menuId, true); + }} /> )} - {props.menuItems && ( - closeContextMenu()} - /> - )} + {props.menuItems && + ReactDOM.createPortal( + closeMenu()} + />, + document.body + )} ); } diff --git a/apps/web/src/utils/useContextMenu.js b/apps/web/src/utils/useContextMenu.js index a91081b93..443ce945d 100644 --- a/apps/web/src/utils/useContextMenu.js +++ b/apps/web/src/utils/useContextMenu.js @@ -1,5 +1,6 @@ import { useEffect, useRef } from "react"; var oldOpenedMenu; +var isOpening = false; function isMouseInside(e, element) { if (!e || !element) return false; @@ -12,13 +13,8 @@ function contextMenuHandler(event, ref, menuId) { !isMouseInside(event, oldOpenedMenu) ) { dismissMenu(oldOpenedMenu); - event.preventDefault(); - const menu = document.getElementById(menuId); - if (!menu) return; - menu.style.display = "block"; - positionMenu(event, menu); - oldOpenedMenu = menu; + openMenu(event, menuId); } } @@ -27,11 +23,29 @@ function onKeyDown(event) { } function onClick() { + if (isOpening) { + isOpening = false; + return; + } dismissMenu(oldOpenedMenu); } function dismissMenu(menu) { - if (menu) menu.style.display = "none"; + if (menu) { + menu.style.display = "none"; + oldOpenedMenu = undefined; + } +} + +function openMenu(event, menuId, withOnClick = false) { + if (withOnClick) { + isOpening = true; + } + const menu = document.getElementById(menuId); + if (!menu) return; + menu.style.display = "block"; + positionMenu(event, menu); + oldOpenedMenu = menu; } function useContextMenu(menuId) { @@ -46,7 +60,7 @@ function useContextMenu(menuId) { parent.removeEventListener("contextmenu", handler); }; }); - return [ref, onClick]; + return [ref, onClick, openMenu]; } function getPosition(e) { @@ -68,8 +82,8 @@ function getPosition(e) { } return { - x: posx - 50, - y: posy - 100, + x: posx, + y: posy, }; } From f2b181a751adba505e66294eaec2bf5734c5c1b3 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 13:28:31 +0500 Subject: [PATCH 361/394] fix: each item should have a unique key prop --- apps/web/src/components/note/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index dcd3b0693..de209523f 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -14,7 +14,7 @@ import Colors from "../menu/colors"; function menuItems(note, context) { return [ - { component: Colors }, + { title: "colors", component: Colors }, { title: note.notebook ? "Move" : "Add to", onClick: async () => { From 4760b706b16c431e7f67446710795f230bb43787 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 14:10:17 +0500 Subject: [PATCH 362/394] fix: pin/unpin causing a crash --- apps/web/src/views/Home.js | 16 +++++++++------- apps/web/yarn.lock | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js index dc93b09a7..76dbdb19a 100644 --- a/apps/web/src/views/Home.js +++ b/apps/web/src/views/Home.js @@ -9,8 +9,9 @@ import NotesPlaceholder from "../components/placeholders/notesplacholder"; function Home() { useEffect(() => store.refresh(), []); - const notes = useStore(store => store.notes); - const newSession = useEditorStore(store => store.newSession); + const notes = useStore((store) => store.notes); + const newSession = useEditorStore((store) => store.newSession); + console.log(notes); return ( - notes.groups[groupIndex].title === "Pinned" ? ( + group={(groupIndex) => { + if (!notes.groups[groupIndex]) return; + return notes.groups[groupIndex].title === "Pinned" ? ( ) : ( @@ -38,8 +40,8 @@ function Home() { {notes.groups[groupIndex].title} - ) - } + ); + }} item={(index, groupIndex) => notes.groupCounts[groupIndex] && ( diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 97ced67a2..9ce497921 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7253,7 +7253,7 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: "notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": version "1.3.0" - resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#f19e76f63dfdf2b9b9914d19ebf139a93dba63c1" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#ed5ead55bed5ff5ec976ed46dc517854b407aff7" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From db1b58e597dbfc4e8ec605d29771a87b35858cc3 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 14:15:24 +0500 Subject: [PATCH 363/394] fix: crash when perm removing item from trash --- apps/web/src/components/list-container/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 24a1a039f..1a2533c3b 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -8,9 +8,9 @@ import { useStore as useSearchStore } from "../../stores/searchstore"; import { useStore as useSelectionStore } from "../../stores/selection-store"; function ListContainer(props) { - const setSearchContext = useSearchStore(store => store.setSearchContext); - const shouldSelectAll = useSelectionStore(store => store.shouldSelectAll); - const setSelectedItems = useSelectionStore(store => store.setSelectedItems); + const setSearchContext = useSearchStore((store) => store.setSearchContext); + const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll); + const setSelectedItems = useSelectionStore((store) => store.setSelectedItems); useEffect(() => { if (shouldSelectAll) setSelectedItems(props.items); @@ -20,7 +20,7 @@ function ListContainer(props) { setSearchContext({ items: props.items, item: props.item, - type: props.type + type: props.type, }); }, [setSearchContext, props.item, props.items, props.type, props.noSearch]); @@ -34,18 +34,18 @@ function ListContainer(props) { <> {!props.noSearch && } - {props.children || ( + {props.children || props.items.length > 0 ? ( props.item(index, props.items[index])} + item={(index) => props.item(index, props.items[index])} /> - )} + ) : null} )} From d69d11b0e01644242861f0c0cdc542be1e2169d7 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Thu, 16 Apr 2020 14:18:00 +0500 Subject: [PATCH 364/394] ui: fix cursor not changing to pointer in menu --- apps/web/src/components/menu/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index 0a265c40e..1cdfd1ab7 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -49,6 +49,7 @@ function Menu(props) { px={3} sx={{ color: item.color || "text", + cursor: "pointer", ":hover": { backgroundColor: "shade", }, From c7dd6b5d4925160149b93f25dd6db54e96cdd9c2 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Fri, 17 Apr 2020 12:52:55 +0500 Subject: [PATCH 365/394] chore: add missing packages --- apps/web/package.json | 9 ++++-- apps/web/src/components/menu/index.js | 1 - apps/web/yarn.lock | 40 +++++++++++++++++++-------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 2909b357b..dc3a275db 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,6 +7,7 @@ "@mdi/react": "^1.4.0", "@rebass/forms": "^4.0.6", "emotion-theming": "^10.0.19", + "fast-sort": "^2.1.1", "framer-motion": "^1.10.3", "immer": "^6.0.3", "libsodium-wrappers": "0.7.6", @@ -15,7 +16,6 @@ "notes-core": "npm:@streetwriters/notesnook-core@latest", "quill": "https://github.com/thecodrr/quill.git#1.3.7", "quill-magic-url": "^1.0.3", - "quill-markdown-shortcuts": "^0.0.10", "react": "^16.13.1", "react-app-polyfill": "^1.0.6", "react-dom": "^16.13.1", @@ -27,8 +27,13 @@ "zustand": "^2.2.3" }, "devDependencies": { - "babel-loader": "8.1.0", + "babel-eslint": "^10.1.0", "eslint": "^6.8.0", + "eslint-config-react-app": "^5.2.1", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^3.0.0", "typescript": "^3.8.3" }, "scripts": { diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index 1cdfd1ab7..d92237663 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -35,7 +35,6 @@ function Menu(props) { key={item.title} onClick={(e) => { e.stopPropagation(); - //Dropdown.closeLastOpened(); if (props.closeMenu) { props.closeMenu(); } diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 9ce497921..b4d354887 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -2264,7 +2264,7 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@10.1.0: +babel-eslint@10.1.0, babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== @@ -4151,7 +4151,25 @@ eslint-plugin-import@2.20.1: read-pkg-up "^2.0.0" resolve "^1.12.0" -eslint-plugin-jsx-a11y@6.2.3: +eslint-plugin-import@^2.20.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" + integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== + dependencies: + array-includes "^3.0.3" + array.prototype.flat "^1.2.1" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.1" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.0" + read-pkg-up "^2.0.0" + resolve "^1.12.0" + +eslint-plugin-jsx-a11y@6.2.3, eslint-plugin-jsx-a11y@^6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== @@ -4171,7 +4189,12 @@ eslint-plugin-react-hooks@^1.6.1: resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== -eslint-plugin-react@7.19.0: +eslint-plugin-react-hooks@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-3.0.0.tgz#9e80c71846eb68dd29c3b21d832728aa66e5bd35" + integrity sha512-EjxTHxjLKIBWFgDJdhKKzLh5q+vjTFrqNZX36uIxWS4OfyXe5DawqPj3U5qeJ1ngLwatjzQnmR0Lz0J0YH3kxw== + +eslint-plugin-react@7.19.0, eslint-plugin-react@^7.19.0: version "7.19.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666" integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ== @@ -4526,7 +4549,7 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-sort@^2.0.1: +fast-sort@^2.0.1, fast-sort@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/fast-sort/-/fast-sort-2.1.1.tgz#b44f908b5bc28c442986682098eb879dba7f07f9" integrity sha512-X8DNrUzoejZZ+AdAHCVXdKHUrbzz57jKG5/prsKKzyaVKwzSwzm0HQ76cPdo69LObWDShJ77Cn1nPMSXP87FOQ== @@ -8762,14 +8785,7 @@ quill-magic-url@^1.0.3: normalize-url "^3.0.1" quill-delta "^3.6.2" -quill-markdown-shortcuts@^0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/quill-markdown-shortcuts/-/quill-markdown-shortcuts-0.0.10.tgz#00ca3e7b48e26f6771cb8f81678d02f9b719b7c9" - integrity sha512-2FFFqqo65JgDgAGSer7cFQTCeiSjJF4N8lRGXGv/xjppCxSwj42OnNdGPZ/zeeCxdUY/j1LW4AiSvPQaTIkY2A== - dependencies: - quill "^1.3.1" - -quill@^1.3.1, "quill@https://github.com/thecodrr/quill.git#1.3.7": +"quill@https://github.com/thecodrr/quill.git#1.3.7": version "1.3.7" resolved "https://github.com/thecodrr/quill.git#adbb4f12348764ceca69deaf3c507d8601fdea6e" dependencies: From 014146982e81d66deeb8538d029f59addd9d2d32 Mon Sep 17 00:00:00 2001 From: alihamuh Date: Sun, 19 Apr 2020 12:34:27 +0500 Subject: [PATCH 366/394] fix: fixed note taking in menus --- apps/web/src/components/navigation-menu/index.js | 6 +++++- apps/web/src/navigation/index.js | 2 +- .../src/navigation/navigators/rootnavigator.js | 2 +- apps/web/src/stores/editor-store.js | 11 +++++++++-- apps/web/src/stores/note-store.js | 1 + apps/web/src/views/Notebooks.js | 15 +++++++++------ apps/web/src/views/Notes.js | 1 + apps/web/src/views/Topics.js | 15 +++++++++------ apps/web/yarn.lock | 4 ++-- 9 files changed, 38 insertions(+), 19 deletions(-) diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js index dfca820db..9a38a7b13 100644 --- a/apps/web/src/components/navigation-menu/index.js +++ b/apps/web/src/components/navigation-menu/index.js @@ -74,7 +74,11 @@ function NavigationMenu(props) { setSelectedRoute(undefined); RootNavigator.navigate("color", { title: toTitleCase(color.title), - context: { type: "color", colors: [color.title] }, + context: { + type: "color", + colors: [color.title], + value: color.title, + }, }); }} key={color.title} diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 57d2430e1..ad0b0e7d8 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -115,7 +115,7 @@ function NavigationContainer(props) { {props.canGoBack && ( diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index b5abb14be..a1d564fb0 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -54,7 +54,7 @@ export const routes = { options: SelectionModeOptions.FavoritesOptions, }, { - context: { type: "favorites" }, + context: { type: "favorites", favorite: true }, } ), ...createNormalRoute("trash", Trash, Icon.Trash, { diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index 720623169..3a219a2b0 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -74,12 +74,17 @@ class EditorStore extends BaseStore { saveSession = (oldSession) => { this.set((state) => (state.session.isSaving = true)); - this._saveFn()(this.get().session).then((id) => { + this._saveFn()(this.get().session).then(async (id) => { if (oldSession) { if (oldSession.tags.length !== this.get().session.tags.length) tagStore.refresh(); if (oldSession.colors.length !== this.get().session.colors.length) appStore.refreshColors(); + + if (oldSession.notebook) + if (oldSession.state === "new" && oldSession.notebook.topic) { + await db.notes.move(oldSession.notebook, id); + } } if (!this.get().session.id) { @@ -115,12 +120,14 @@ class EditorStore extends BaseStore { clearTimeout(this.get().session.timeout); const oldSession = { ...this.get().session }; this.set((state) => { - state.session.state = SESSION_STATES.stale; set(state); state.session.timeout = setTimeout( () => { this.session = this.get().session; + this.set((state) => { + state.session.state = SESSION_STATES.stale; + }); this.saveSession(oldSession); }, immediate ? 0 : 500 diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index b926e6069..405c45c79 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -36,6 +36,7 @@ class NoteStore extends BaseStore { break; case "color": notes = db.notes.colored(context.value); + //console.log(context.value, " I am in notesStore"); break; case "topic": notes = db.notebooks diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index ebdb0cde2..cbc79a2b8 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -10,8 +10,8 @@ import NotebooksPlaceholder from "../components/placeholders/notebooks-placehold function Notebooks(props) { const [open, setOpen] = useState(false); useEffect(() => store.refresh(), []); - const notebooks = useStore(state => state.notebooks); - const add = useStore(state => state.add); + const notebooks = useStore((state) => state.notebooks); + const add = useStore((state) => state.add); return ( <> @@ -34,7 +34,10 @@ function Notebooks(props) { subtitle: topic.title, notes: db.notebooks .notebook(notebook.id) - .topics.topic(topic.title).all + .topics.topic(topic.title).all, + context: { + notebook: { id: notebook.id, topic: topic.title }, + }, }) } /> @@ -44,12 +47,12 @@ function Notebooks(props) { content: "Create a notebook", onClick: async () => { setOpen(true); - } + }, }} /> { + onDone={async (nb) => { await add(nb); setOpen(false); }} diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index c54655e1c..b403908be 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -16,6 +16,7 @@ function Notes(props) { } }, [props.context, setContext]); + console.log(context); if (!context) return null; return ( store.setContext); + const setContext = useNoteStore((store) => store.setContext); const setSelectedNotebookTopics = useNbStore( - store => store.setSelectedNotebookTopics + (store) => store.setSelectedNotebookTopics ); const selectedNotebookTopics = useNbStore( - store => store.selectedNotebookTopics + (store) => store.selectedNotebookTopics ); const [topics, setTopics] = useState([]); @@ -37,11 +37,14 @@ function Topics(props) { setContext({ type: "topic", value: topic.title, - notebook: props.notebook + notebook: props.notebook, }); props.navigator.navigate("notes", { title: props.notebook.title, - subtitle: topic.title + subtitle: topic.title, + context: { + notebook: { id: props.notebook.id, topic: topic.title }, + }, }); }} /> @@ -51,7 +54,7 @@ function Topics(props) { content: "Add more topics", onClick: async () => { await showTopicDialog(props.notebook.id); - } + }, }} /> ); diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index b4d354887..28c22b15c 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7274,9 +7274,9 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -"notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": +"notes-core@https://github.com/streetwriters/notesnook-core.git": version "1.3.0" - resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#ed5ead55bed5ff5ec976ed46dc517854b407aff7" + resolved "https://github.com/streetwriters/notesnook-core.git#ed5ead55bed5ff5ec976ed46dc517854b407aff7" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From b4520d2a0dd2e6c8b9dcdf8516c45948eb34b61d Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 19 Apr 2020 13:23:22 +0500 Subject: [PATCH 367/394] perf: reduce libsodium dep size --- apps/web/package.json | 3 +- apps/web/src/interfaces/crypto.js | 2 +- apps/web/yarn.lock | 109 ++++++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index dc3a275db..8b118855b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,7 +10,7 @@ "fast-sort": "^2.1.1", "framer-motion": "^1.10.3", "immer": "^6.0.3", - "libsodium-wrappers": "0.7.6", + "libsodium-wrappers": "https://github.com/streetwriters/libsodium-packages.git#libsodium-wrappers", "localforage": "^1.7.3", "localforage-getitems": "https://github.com/thecodrr/localForage-getItems.git", "notes-core": "npm:@streetwriters/notesnook-core@latest", @@ -34,6 +34,7 @@ "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-react": "^7.19.0", "eslint-plugin-react-hooks": "^3.0.0", + "source-map-explorer": "^2.4.2", "typescript": "^3.8.3" }, "scripts": { diff --git a/apps/web/src/interfaces/crypto.js b/apps/web/src/interfaces/crypto.js index 3b3569ed9..ef31bcc56 100644 --- a/apps/web/src/interfaces/crypto.js +++ b/apps/web/src/interfaces/crypto.js @@ -5,7 +5,7 @@ class Crypto { } async _initialize() { if (this.isReady) return; - const _sodium = require("libsodium-wrappers"); + const { default: _sodium } = await import("libsodium-wrappers"); await _sodium.ready; this.sodium = _sodium; this.isReady = true; diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 28c22b15c..82623ee24 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -2026,7 +2026,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== @@ -2669,6 +2669,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -2991,6 +2996,15 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + clone-deep@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" @@ -3921,6 +3935,11 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +ejs@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.0.2.tgz#745b01cdcfe38c1c6a2da3bbb2d9957060a31226" + integrity sha512-IncmUpn1yN84hy2shb0POJ80FWrfGNY0cxO9f4v+/sG7qcBvAtVWUA1IdzY/8EYUmOVhoKJVdJjNd3AZcnxOjA== + electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.390: version "1.3.405" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.405.tgz#b84fcb157edb26eae6c36d93d416cb51caa399bd" @@ -4065,7 +4084,7 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3: d "^1.0.1" ext "^1.1.2" -escape-html@~1.0.3: +escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= @@ -4683,7 +4702,7 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@4.1.0, find-up@^4.0.0: +find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -5051,7 +5070,7 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -gzip-size@5.1.1: +gzip-size@5.1.1, gzip-size@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== @@ -6606,17 +6625,15 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libsodium-wrappers@0.7.6: +"libsodium-wrappers@https://github.com/streetwriters/libsodium-packages.git#libsodium-wrappers": version "0.7.6" - resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.6.tgz#baed4c16d4bf9610104875ad8a8e164d259d48fb" - integrity sha512-OUO2CWW5bHdLr6hkKLHIKI4raEkZrf3QHkhXsJ1yCh6MZ3JDA7jFD3kCATNquuGSG6MjjPHQIQms0y0gBDzjQg== + resolved "https://github.com/streetwriters/libsodium-packages.git#bebd2159d1dc09ded6191f87f3da6cadb4cdc446" dependencies: - libsodium "0.7.6" + libsodium "https://github.com/streetwriters/libsodium-packages.git#libsodium" -libsodium@0.7.6: +"libsodium@https://github.com/streetwriters/libsodium-packages.git#libsodium": version "0.7.6" - resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.6.tgz#018b80c5728054817845fbffa554274441bda277" - integrity sha512-hPb/04sEuLcTRdWDtd+xH3RXBihpmbPCsKW/Jtf4PsvdyKh+D6z2D2gvp/5BfoxseP+0FCOg66kE+0oGUE/loQ== + resolved "https://github.com/streetwriters/libsodium-packages.git#a03b519a026175379bfc881e0b6a2724a42867ae" lie@3.1.1: version "3.1.1" @@ -7449,7 +7466,7 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^7.0.2: +open@^7.0.2, open@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== @@ -9373,7 +9390,7 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2.6.3: +rimraf@2.6.3, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -9785,6 +9802,24 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== +source-map-explorer@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.4.2.tgz#fb23f86c3112eacde5683f24efaf4ddc9f677985" + integrity sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ== + dependencies: + btoa "^1.2.1" + chalk "^3.0.0" + convert-source-map "^1.7.0" + ejs "^3.0.2" + escape-html "^1.0.3" + glob "^7.1.6" + gzip-size "^5.1.1" + lodash "^4.17.15" + open "^7.0.3" + source-map "^0.7.3" + temp "^0.9.1" + yargs "^15.3.1" + source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -9819,6 +9854,11 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + spdx-correct@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" @@ -10017,7 +10057,7 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -10271,6 +10311,13 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +temp@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697" + integrity sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA== + dependencies: + rimraf "~2.6.2" + terser-webpack-plugin@2.3.5: version "2.3.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz#5ad971acce5c517440ba873ea4f09687de2f4a81" @@ -11146,6 +11193,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -11241,6 +11297,14 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^18.1.1: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs@12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" @@ -11275,6 +11339,23 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@^15.3.1: + version "15.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" + integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.1" + zustand@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/zustand/-/zustand-2.2.3.tgz#07ee668bf600a5e0dcff8f8b60f35faa149f65d5" From 0933a34a4172b8bd972b3ea1f9fc1de27ab0b86f Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 19 Apr 2020 13:25:41 +0500 Subject: [PATCH 368/394] ci: use ssh url for notes-core From a7b568d1083501fe920938e28e3ed09336513251 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 19 Apr 2020 14:16:01 +0500 Subject: [PATCH 369/394] refactor: cleanup context logic --- .../src/components/navigation-menu/index.js | 1 - .../navigation/navigators/rootnavigator.js | 2 +- apps/web/src/stores/editor-store.js | 20 ++++++++++--------- apps/web/src/stores/note-store.js | 5 ++--- apps/web/src/views/Home.js | 1 - apps/web/src/views/Notes.js | 7 +------ apps/web/src/views/Tags.js | 5 +---- apps/web/src/views/Topics.js | 10 ++-------- 8 files changed, 18 insertions(+), 33 deletions(-) diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js index 9a38a7b13..190537c50 100644 --- a/apps/web/src/components/navigation-menu/index.js +++ b/apps/web/src/components/navigation-menu/index.js @@ -76,7 +76,6 @@ function NavigationMenu(props) { title: toTitleCase(color.title), context: { type: "color", - colors: [color.title], value: color.title, }, }); diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index a1d564fb0..b5abb14be 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -54,7 +54,7 @@ export const routes = { options: SelectionModeOptions.FavoritesOptions, }, { - context: { type: "favorites", favorite: true }, + context: { type: "favorites" }, } ), ...createNormalRoute("trash", Trash, Icon.Trash, { diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index 3a219a2b0..ec18b8a78 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -20,6 +20,7 @@ const DEFAULT_SESSION = { favorite: false, locked: false, tags: [], + context: undefined, colors: [], dateEdited: 0, content: { @@ -75,16 +76,19 @@ class EditorStore extends BaseStore { saveSession = (oldSession) => { this.set((state) => (state.session.isSaving = true)); this._saveFn()(this.get().session).then(async (id) => { - if (oldSession) { + storeSync: if (oldSession) { if (oldSession.tags.length !== this.get().session.tags.length) tagStore.refresh(); + if (oldSession.colors.length !== this.get().session.colors.length) appStore.refreshColors(); - if (oldSession.notebook) - if (oldSession.state === "new" && oldSession.notebook.topic) { - await db.notes.move(oldSession.notebook, id); - } + if (oldSession.state !== "new" || !oldSession.context) break storeSync; + + const { type, value } = oldSession.context; + if (type === "topic") await db.notes.move(value, id); + else if (type === "color") await db.notes.note(id).color(value); + else if (type === "tag") await db.notes.note(id).tag(value); } if (!this.get().session.id) { @@ -108,7 +112,7 @@ class EditorStore extends BaseStore { this.set(function (state) { state.session = { ...DEFAULT_SESSION, - ...context, + context, state: SESSION_STATES.new, }; }); @@ -124,10 +128,8 @@ class EditorStore extends BaseStore { state.session.timeout = setTimeout( () => { + this.set((state) => (state.session.state = SESSION_STATES.stale)); this.session = this.get().session; - this.set((state) => { - state.session.state = SESSION_STATES.stale; - }); this.saveSession(oldSession); }, immediate ? 0 : 500 diff --git a/apps/web/src/stores/note-store.js b/apps/web/src/stores/note-store.js index 405c45c79..6c61543cc 100644 --- a/apps/web/src/stores/note-store.js +++ b/apps/web/src/stores/note-store.js @@ -36,12 +36,11 @@ class NoteStore extends BaseStore { break; case "color": notes = db.notes.colored(context.value); - //console.log(context.value, " I am in notesStore"); break; case "topic": notes = db.notebooks - .notebook(context.notebook.id) - .topics.topic(context.value).all; + .notebook(context.value.id) + .topics.topic(context.value.topic).all; break; case "favorites": notes = db.notes.favorites; diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js index 76dbdb19a..94b0d8102 100644 --- a/apps/web/src/views/Home.js +++ b/apps/web/src/views/Home.js @@ -11,7 +11,6 @@ function Home() { useEffect(() => store.refresh(), []); const notes = useStore((store) => store.notes); const newSession = useEditorStore((store) => store.newSession); - console.log(notes); return ( - newSession({ - ...DEFAULT_CONTEXT, - ...props.context, - }), + onClick: () => newSession(props.context), }} /> ); diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index cf53de167..fccec54c6 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -2,7 +2,6 @@ import React, { useEffect } from "react"; import { Flex, Text } from "rebass"; import ListContainer from "../components/list-container"; import ListItem from "../components/list-item"; -import { useStore as useNotesStore } from "../stores/note-store"; import { useStore, store } from "../stores/tag-store"; import TagsPlaceholder from "../components/placeholders/tags-placeholder"; @@ -18,7 +17,6 @@ function TagNode({ title }) { } function Tags(props) { - const setContext = useNotesStore((store) => store.setContext); const tags = useStore((store) => store.tags); useEffect(() => { store.refresh(); @@ -37,10 +35,9 @@ function Tags(props) { title={} info={`${noteIds.length} notes`} onClick={() => { - setContext({ type: "tag", value: title }); props.navigator.navigate("notes", { title: "#" + title, - context: { tags: [title] }, + context: { type: "tag", value: title }, }); }} /> diff --git a/apps/web/src/views/Topics.js b/apps/web/src/views/Topics.js index bf44a5c27..c24069731 100644 --- a/apps/web/src/views/Topics.js +++ b/apps/web/src/views/Topics.js @@ -2,12 +2,10 @@ import React, { useState, useEffect } from "react"; import Topic from "../components/topic"; import { Flex } from "rebass"; import ListContainer from "../components/list-container"; -import { useStore as useNoteStore } from "../stores/note-store"; import { useStore as useNbStore } from "../stores/notebook-store"; import { showTopicDialog } from "../components/dialogs/topicdialog"; function Topics(props) { - const setContext = useNoteStore((store) => store.setContext); const setSelectedNotebookTopics = useNbStore( (store) => store.setSelectedNotebookTopics ); @@ -34,16 +32,12 @@ function Topics(props) { item={item} onClick={() => { let topic = item; - setContext({ - type: "topic", - value: topic.title, - notebook: props.notebook, - }); props.navigator.navigate("notes", { title: props.notebook.title, subtitle: topic.title, context: { - notebook: { id: props.notebook.id, topic: topic.title }, + type: "topic", + value: { id: props.notebook.id, topic: topic.title }, }, }); }} From a57db4b590183bc44224bb78c4fe385deecda90e Mon Sep 17 00:00:00 2001 From: thecodrr Date: Sun, 19 Apr 2020 14:16:58 +0500 Subject: [PATCH 370/394] fix: resolve all warnings --- apps/web/src/stores/editor-store.js | 2 ++ apps/web/src/views/Notes.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index ec18b8a78..c52341940 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -76,6 +76,7 @@ class EditorStore extends BaseStore { saveSession = (oldSession) => { this.set((state) => (state.session.isSaving = true)); this._saveFn()(this.get().session).then(async (id) => { + /* eslint-disable */ storeSync: if (oldSession) { if (oldSession.tags.length !== this.get().session.tags.length) tagStore.refresh(); @@ -90,6 +91,7 @@ class EditorStore extends BaseStore { else if (type === "color") await db.notes.note(id).color(value); else if (type === "tag") await db.notes.note(id).tag(value); } + /* eslint-enable */ if (!this.get().session.id) { noteStore.setSelectedNote(id); diff --git a/apps/web/src/views/Notes.js b/apps/web/src/views/Notes.js index 7614280a7..043ed6a3d 100644 --- a/apps/web/src/views/Notes.js +++ b/apps/web/src/views/Notes.js @@ -3,7 +3,6 @@ import Note from "../components/note"; import ListContainer from "../components/list-container"; import { useStore } from "../stores/editor-store"; import { useStore as useNotesStore } from "../stores/note-store"; -import { DEFAULT_CONTEXT } from "../common"; function Notes(props) { const newSession = useStore((store) => store.newSession); From 7c0b7d3b5ecc75f2d0d60a65b34d06fcfb6d2ec2 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 11:20:42 +0500 Subject: [PATCH 371/394] navigation: simplify nested navigation --- apps/web/src/app.js | 10 +- .../editor/modules/markdown/index.js | 29 ++--- .../src/components/navigation-menu/index.js | 7 +- apps/web/src/components/notebook/index.js | 1 - apps/web/src/navigation/container.js | 10 ++ apps/web/src/navigation/index.js | 121 +++--------------- .../src/navigation/navigators/nbnavigator.js | 12 +- .../navigation/navigators/rootnavigator.js | 31 ++--- apps/web/src/navigation/route.js | 102 +++++++++++++++ apps/web/src/navigation/routes.js | 10 +- apps/web/src/views/Notebooks.js | 21 ++- apps/web/src/views/Settings.js | 15 +-- apps/web/src/views/Tags.js | 15 +-- apps/web/src/views/index.js | 9 +- 14 files changed, 197 insertions(+), 196 deletions(-) create mode 100644 apps/web/src/navigation/container.js create mode 100644 apps/web/src/navigation/route.js diff --git a/apps/web/src/app.js b/apps/web/src/app.js index efcfcafb2..7820905d5 100644 --- a/apps/web/src/app.js +++ b/apps/web/src/app.js @@ -9,6 +9,8 @@ import { useStore as useEditorStore } from "./stores/editor-store"; import { useStore as useUserStore } from "./stores/user-store"; import Animated from "./components/animated"; import NavigationMenu from "./components/navigationmenu"; +import NavigationContainer from "./navigation/container"; +import RootNavigator from "./navigation/navigators/rootnavigator"; function App() { const [show, setShow] = usePersistentState("isContainerVisible", true); @@ -42,7 +44,6 @@ function App() { + > + + diff --git a/apps/web/src/components/editor/modules/markdown/index.js b/apps/web/src/components/editor/modules/markdown/index.js index e8efecd10..2bd55c7e5 100644 --- a/apps/web/src/components/editor/modules/markdown/index.js +++ b/apps/web/src/components/editor/modules/markdown/index.js @@ -50,7 +50,7 @@ class MarkdownShortcuts { this.quill.formatLine(selection.index, 0, "header", size - 1); this.quill.deleteText(selection.index - size, size); }, 0); - } + }, }, { name: "blockquote", @@ -61,7 +61,7 @@ class MarkdownShortcuts { this.quill.formatLine(selection.index, 1, "blockquote", true); this.quill.deleteText(selection.index - 2, 2); }, 0); - } + }, }, { name: "code-block", @@ -72,7 +72,7 @@ class MarkdownShortcuts { this.quill.formatLine(selection.index, 1, "code-block", true); this.quill.deleteText(selection.index - 4, 4); }, 0); - } + }, }, { name: "bolditalic", @@ -90,11 +90,11 @@ class MarkdownShortcuts { this.quill.deleteText(startIndex, annotatedText.length); this.quill.insertText(startIndex, matchedText, { bold: true, - italic: true + italic: true, }); this.quill.format("bold", false); }, 0); - } + }, }, { name: "bold", @@ -113,7 +113,7 @@ class MarkdownShortcuts { this.quill.insertText(startIndex, matchedText, { bold: true }); this.quill.format("bold", false); }, 0); - } + }, }, { name: "italic", @@ -132,7 +132,7 @@ class MarkdownShortcuts { this.quill.insertText(startIndex, matchedText, { italic: true }); this.quill.format("italic", false); }, 0); - } + }, }, { name: "strikethrough", @@ -151,7 +151,7 @@ class MarkdownShortcuts { this.quill.insertText(startIndex, matchedText, { strike: true }); this.quill.format("strike", false); }, 0); - } + }, }, { name: "code", @@ -171,7 +171,7 @@ class MarkdownShortcuts { this.quill.format("code", false); this.quill.insertText(this.quill.getSelection(), " "); }, 0); - } + }, }, { name: "hr", @@ -190,7 +190,7 @@ class MarkdownShortcuts { this.quill.insertText(startIndex + 2, "\n", Quill.sources.SILENT); this.quill.setSelection(startIndex + 2, Quill.sources.SILENT); }, 0); - } + }, }, { name: "asterisk-ul", @@ -199,14 +199,13 @@ class MarkdownShortcuts { setTimeout(() => { let index = selection.index; this.quill.formatLine(index, 1, "list", "unordered"); - console.log(text, selection, pattern); if (text.trim() === "*") { this.quill.deleteText(index, 1); } else if (text.trim() === "+") { this.quill.deleteText(index - 2, 2); } }, 0); - } + }, }, { name: "image", @@ -227,7 +226,7 @@ class MarkdownShortcuts { ); }, 0); } - } + }, }, { name: "link", @@ -249,8 +248,8 @@ class MarkdownShortcuts { ); }, 0); } - } - } + }, + }, ]; // Handler that looks for insert deltas that match specific characters diff --git a/apps/web/src/components/navigation-menu/index.js b/apps/web/src/components/navigation-menu/index.js index 190537c50..d4dcf05fc 100644 --- a/apps/web/src/components/navigation-menu/index.js +++ b/apps/web/src/components/navigation-menu/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import { Box } from "rebass"; import RootNavigator, { bottomRoutes, @@ -21,11 +21,6 @@ function NavigationMenu(props) { const colors = useStore((store) => store.colors); const isSideMenuOpen = useStore((store) => store.isSideMenuOpen); - useEffect(() => { - RootNavigator.navigate(selectedRoute); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return ( { + props.navigator.onLoad(); + }, [props.navigator]); + return ; +} +export default NavigationContainer; diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index ad0b0e7d8..eb9091013 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -1,12 +1,10 @@ import React from "react"; import ReactDOM from "react-dom"; -import { Box, Flex, Heading, Text } from "rebass"; import Animated from "../components/animated"; import { AnimatePresence } from "framer-motion"; -import * as Icon from "../components/icons"; -import ThemeProvider from "../components/theme-provider"; -import { useStore } from "../stores/app-store"; import { store as selectionStore } from "../stores/selection-store"; +import Route from "./route"; +import Config from "../utils/config"; class Navigator { constructor(root, routes, options = {}) { @@ -17,10 +15,24 @@ class Navigator { this.lastRoute = undefined; } + onLoad = () => { + const route = Config.get(this.root, this.getRoute(this.options.default)); + this.navigate(route.key, route.params); + }; + getRoute(key) { return this.routes[key]; } + setLastRoute(route) { + this.lastRoute = route; + // cache the route in localStorage + // NOTE: we delete the navigator key if any so it's always new across refreshes + const copy = { ...route, params: { ...route.params } }; + if (copy.params.navigator) delete copy.params.navigator; + Config.set(this.root, copy); + } + getRoot() { return document.querySelector(`.${this.root}`); } @@ -37,7 +49,7 @@ class Navigator { if (this.lastRoute) { this.history.push(this.lastRoute); } - this.lastRoute = route; + this.setLastRoute(route); return this.renderRoute(route); } @@ -59,7 +71,7 @@ class Navigator { flexDirection="column" flex="1 1 auto" > - store.toggleSideMenu); - const isSelectionMode = useStore((store) => store.isSelectionMode); - const exitSelectionMode = useStore((store) => store.exitSelectionMode); - const selectAll = useStore((store) => store.selectAll); - return ( - - - {(props.route.title || props.route.params.title) && ( - <> - - - {props.canGoBack && ( - - - - )} - - - - - {props.route.title || props.route.params.title} - - - {props.route.options && isSelectionMode && ( - - {props.route.options.map((option) => ( - - - - ))} - - )} - - {props.route.params.subtitle && ( - - {props.route.params.subtitle} - - )} - {isSelectionMode && ( - - selectAll()} - > - Select all - - exitSelectionMode()} - > - Unselect - - - )} - - )} - - {props.route.component && ( - - )} - - ); -} diff --git a/apps/web/src/navigation/navigators/nbnavigator.js b/apps/web/src/navigation/navigators/nbnavigator.js index 4d689bc33..8e3fde29b 100644 --- a/apps/web/src/navigation/navigators/nbnavigator.js +++ b/apps/web/src/navigation/navigators/nbnavigator.js @@ -6,16 +6,18 @@ import SelectionModeOptions from "../../common/selectionoptions"; const routes = { ...createRoute("notebooks", Notebooks, { title: "Notebooks", - options: SelectionModeOptions.NotebooksOptions + options: SelectionModeOptions.NotebooksOptions, }), ...createRoute("topics", Topics, { - options: SelectionModeOptions.TopicOptions + options: SelectionModeOptions.TopicOptions, + }), + ...createRoute("notes", Notes, { + options: SelectionModeOptions.NotesOptions, }), - ...createRoute("notes", Notes, { options: SelectionModeOptions.NotesOptions }) }; const NotebookNavigator = new Navigator("NotebookNavigator", routes, { - backButtonEnabled: true + backButtonEnabled: true, + default: "notebooks", }); - export default NotebookNavigator; diff --git a/apps/web/src/navigation/navigators/rootnavigator.js b/apps/web/src/navigation/navigators/rootnavigator.js index b5abb14be..e6410029b 100644 --- a/apps/web/src/navigation/navigators/rootnavigator.js +++ b/apps/web/src/navigation/navigators/rootnavigator.js @@ -1,20 +1,18 @@ -import { - Home, - SettingsContainer, - Trash, - NotebooksContainer, - TagsContainer, - Notes, - Account, -} from "../../views"; +import { Home, Trash, Notes, Account } from "../../views"; import * as Icon from "../../components/icons"; -import { createRoute, createNormalRoute, createDeadRoute } from "../routes"; +import { + createRoute, + createNavigatorRoute, + createNormalRoute, + createDeadRoute, +} from "../routes"; import Navigator from "../index"; import SelectionModeOptions from "../../common/selectionoptions"; import Search from "../../views/Search"; import { store as userStore } from "../../stores/user-store"; import { store as themeStore } from "../../stores/theme-store"; import { showLogInDialog } from "../../components/dialogs/logindialog"; +import { NotebookNavigator, TagNavigator, SettingsNavigator } from "./index"; export const bottomRoutes = { ...createDeadRoute("nightmode", Icon.Theme, { @@ -32,9 +30,7 @@ export const bottomRoutes = { } else return RootNavigator.navigate("account"); }, }), - ...createRoute("settings", SettingsContainer, { - icon: Icon.Settings, - }), + ...createNavigatorRoute("settings", Icon.Settings, SettingsNavigator), }; export const routes = { @@ -42,9 +38,7 @@ export const routes = { title: "Home", options: SelectionModeOptions.NotesOptions, }), - ...createRoute("notebooks", NotebooksContainer, { - icon: Icon.Notebook, - }), + ...createNavigatorRoute("notebooks", Icon.Notebook, NotebookNavigator), ...createRoute( "favorites", Notes, @@ -61,9 +55,7 @@ export const routes = { title: "Trash", options: SelectionModeOptions.TrashOptions, }), - ...createRoute("tags", TagsContainer, { - icon: Icon.Tag, - }), + ...createNavigatorRoute("tags", Icon.Tag, TagNavigator), }; const invisibleRoutes = { @@ -79,6 +71,7 @@ const RootNavigator = new Navigator( { ...routes, ...bottomRoutes, ...invisibleRoutes }, { backButtonEnabled: false, + default: "home", } ); diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js new file mode 100644 index 000000000..8f1342dae --- /dev/null +++ b/apps/web/src/navigation/route.js @@ -0,0 +1,102 @@ +import React from "react"; +import { Box, Flex, Heading, Text } from "rebass"; +import * as Icon from "../components/icons"; +import ThemeProvider from "../components/theme-provider"; +import { useStore } from "../stores/app-store"; + +function Route(props) { + const toggleSideMenu = useStore((store) => store.toggleSideMenu); + const isSelectionMode = useStore((store) => store.isSelectionMode); + const exitSelectionMode = useStore((store) => store.exitSelectionMode); + const selectAll = useStore((store) => store.selectAll); + const navigator = props.params.navigator || props.navigator; + return ( + + + {(props.route.title || props.route.params.title) && ( + <> + + + {props.canGoBack && ( + + + + )} + + + + + {props.route.title || props.route.params.title} + + + {props.route.options && isSelectionMode && ( + + {props.route.options.map((option) => ( + + + + ))} + + )} + + {props.route.params.subtitle && ( + + {props.route.params.subtitle} + + )} + {isSelectionMode && ( + + selectAll()} + > + Select all + + exitSelectionMode()} + > + Unselect + + + )} + + )} + + {props.route.component && ( + + )} + + ); +} +export default Route; diff --git a/apps/web/src/navigation/routes.js b/apps/web/src/navigation/routes.js index 9e87b8c16..3358f9c01 100644 --- a/apps/web/src/navigation/routes.js +++ b/apps/web/src/navigation/routes.js @@ -1,14 +1,20 @@ +import NavigationContainer from "./container"; + export function createRoute(key, component, props = {}, params = {}) { return { [key]: { key, component, ...props, - params - } + params, + }, }; } +export function createNavigatorRoute(key, icon, navigator) { + return createRoute(key, NavigationContainer, { icon }, { navigator }); +} + export function createNormalRoute(key, component, icon, props = {}) { return createRoute(key, component, { title: component.name, icon, ...props }); } diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index cbc79a2b8..d8385084b 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -1,5 +1,4 @@ import React, { useState, useEffect } from "react"; -import { Flex } from "rebass"; import { db } from "../common"; import Notebook from "../components/notebook"; import AddNotebookDialog from "../components/dialogs/addnotebookdialog"; @@ -64,15 +63,13 @@ function Notebooks(props) { ); } -function NotebooksContainer() { - useEffect(() => { - const NotebookNavigator = require("../navigation/navigators/nbnavigator") - .default; - if (!NotebookNavigator.restore()) { - NotebookNavigator.navigate("notebooks"); - } - }, []); - return ; -} +/* function NotebooksContainer() { + return ( + + ); +} */ -export { NotebooksContainer, Notebooks }; +export default Notebooks; diff --git a/apps/web/src/views/Settings.js b/apps/web/src/views/Settings.js index bbe07af4b..ab9b08b23 100644 --- a/apps/web/src/views/Settings.js +++ b/apps/web/src/views/Settings.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import { Box, Button, Flex, Text } from "rebass"; import * as Icon from "../components/icons"; import { useStore as useUserStore } from "../stores/user-store"; @@ -107,15 +107,4 @@ function Settings(props) { ); } -function SettingsContainer() { - useEffect(() => { - const SettingsNavigator = require("../navigation/navigators/settingnavigator") - .default; - if (!SettingsNavigator.restore()) { - SettingsNavigator.navigate("settings"); - } - }, []); - return ; -} - -export { Settings, SettingsContainer }; +export default Settings; diff --git a/apps/web/src/views/Tags.js b/apps/web/src/views/Tags.js index fccec54c6..b7479c951 100644 --- a/apps/web/src/views/Tags.js +++ b/apps/web/src/views/Tags.js @@ -1,5 +1,5 @@ import React, { useEffect } from "react"; -import { Flex, Text } from "rebass"; +import { Text } from "rebass"; import ListContainer from "../components/list-container"; import ListItem from "../components/list-item"; import { useStore, store } from "../stores/tag-store"; @@ -48,15 +48,4 @@ function Tags(props) { ); } -function TagsContainer() { - useEffect(() => { - const TagNavigator = require("../navigation/navigators/tagnavigator") - .default; - if (!TagNavigator.restore()) { - TagNavigator.navigate("tags"); - } - }, []); - return ; -} - -export { Tags, TagsContainer }; +export default Tags; diff --git a/apps/web/src/views/index.js b/apps/web/src/views/index.js index cc9df9f44..54a0ad7cd 100644 --- a/apps/web/src/views/index.js +++ b/apps/web/src/views/index.js @@ -1,12 +1,9 @@ export const Home = require("./Home").default; -export const NotebooksContainer = require("./Notebooks").NotebooksContainer; -export const Notebooks = require("./Notebooks").Notebooks; +export const Notebooks = require("./Notebooks").default; export const Notes = require("./Notes").default; export const Topics = require("./Topics").default; -export const Settings = require("./Settings").Settings; +export const Settings = require("./Settings").default; export const Trash = require("./Trash").default; export const Account = require("./Account").default; -export const SettingsContainer = require("./Settings").SettingsContainer; -export const Tags = require("./Tags").Tags; -export const TagsContainer = require("./Tags").TagsContainer; +export const Tags = require("./Tags").default; export const Search = require("./Search").default; From d5be85953070a6adbe653056597d0b0724473efd Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 11:24:07 +0500 Subject: [PATCH 372/394] navigation: add default routes for settings & tag navigators After the nested navigation refactor, all routes with their own navigators require a `default` option that configures which route to load on startup. --- apps/web/src/navigation/navigators/settingnavigator.js | 5 +++-- apps/web/src/navigation/navigators/tagnavigator.js | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/web/src/navigation/navigators/settingnavigator.js b/apps/web/src/navigation/navigators/settingnavigator.js index ca9465df0..02bc8c115 100644 --- a/apps/web/src/navigation/navigators/settingnavigator.js +++ b/apps/web/src/navigation/navigators/settingnavigator.js @@ -4,11 +4,12 @@ import { createRoute } from "../routes"; const routes = { ...createRoute("settings", Settings, { title: "Settings" }), - ...createRoute("account", Account, { title: "Account" }) + ...createRoute("account", Account, { title: "Account" }), }; const SettingsNavigator = new Navigator("SettingsNavigator", routes, { - backButtonEnabled: true + backButtonEnabled: true, + default: "settings", }); export default SettingsNavigator; diff --git a/apps/web/src/navigation/navigators/tagnavigator.js b/apps/web/src/navigation/navigators/tagnavigator.js index cfed8730b..8bc1a0ea1 100644 --- a/apps/web/src/navigation/navigators/tagnavigator.js +++ b/apps/web/src/navigation/navigators/tagnavigator.js @@ -5,11 +5,14 @@ import SelectionModeOptions from "../../common/selectionoptions"; const routes = { ...createRoute("tags", Tags, { title: "Tags" }), - ...createRoute("notes", Notes, { options: SelectionModeOptions.NotesOptions }) + ...createRoute("notes", Notes, { + options: SelectionModeOptions.NotesOptions, + }), }; const TagNavigator = new Navigator("TagNavigator", routes, { - backButtonEnabled: true + backButtonEnabled: true, + default: "tags", }); export default TagNavigator; From f9310f9cd3c0a889dc18bacc276ae69eb1131545 Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Mon, 20 Apr 2020 12:04:20 +0500 Subject: [PATCH 373/394] ci: use script/ci.sh to handle ssh keys --- apps/web/.github/workflows/build.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/web/.github/workflows/build.yml b/apps/web/.github/workflows/build.yml index 4f1d4bb07..8cdaa24ce 100644 --- a/apps/web/.github/workflows/build.yml +++ b/apps/web/.github/workflows/build.yml @@ -5,17 +5,14 @@ on: [pull_request, push] jobs: build: runs-on: ubuntu-latest + env: + GH_DEPLOY_KEY: ${{ secrets.GH_DEPLOY_KEY }} steps: - name: Checkout 🛎️ uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly. with: persist-credentials: false - - name: Setup SSH - uses: webfactory/ssh-agent@v0.2.0 - with: - ssh-private-key: ${{ secrets.GH_SSH_KEY }} - - name: Use Node.js 12.x uses: actions/setup-node@v1 with: From f0f209e1f65b9a36e7625a6027c4e0a68c26f4b6 Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Mon, 20 Apr 2020 12:06:02 +0500 Subject: [PATCH 374/394] ci: use script/ci.sh to handle ssh keys --- apps/web/.github/workflows/deploy.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/web/.github/workflows/deploy.yml b/apps/web/.github/workflows/deploy.yml index 832641c91..c591a0109 100644 --- a/apps/web/.github/workflows/deploy.yml +++ b/apps/web/.github/workflows/deploy.yml @@ -17,11 +17,6 @@ jobs: with: persist-credentials: false - - name: Setup SSH - uses: webfactory/ssh-agent@v0.2.0 - with: - ssh-private-key: ${{ secrets.GH_SSH_KEY }} - - name: Use Node.js 12.x uses: actions/setup-node@v1 with: From 5492a92f02b76403995a7b364b45b020cbaf7642 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 12:29:16 +0500 Subject: [PATCH 375/394] navigation: force navigate on load --- apps/web/src/navigation/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index eb9091013..0be43a826 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -17,7 +17,7 @@ class Navigator { onLoad = () => { const route = Config.get(this.root, this.getRoute(this.options.default)); - this.navigate(route.key, route.params); + this.navigate(route.key, route.params, true); }; getRoute(key) { From aa905e20b98216185df0218eba387254cdc177a1 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 12:30:34 +0500 Subject: [PATCH 376/394] ui: adjust default button font size --- apps/web/src/theme/variants/button.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/web/src/theme/variants/button.js b/apps/web/src/theme/variants/button.js index 203a2cc42..f75e87795 100644 --- a/apps/web/src/theme/variants/button.js +++ b/apps/web/src/theme/variants/button.js @@ -8,7 +8,7 @@ class ButtonFactory { list: new List(), anchor: new Anchor(), menu: new Menu(), - icon: new Icon() + icon: new Icon(), }; } } @@ -20,11 +20,12 @@ class Default { bg: "transparent", fontFamily: "body", fontWeight: "body", + fontSize: "body", borderRadius: "default", cursor: "pointer", ":focus": { - outline: "none" - } + outline: "none", + }, }; } } @@ -37,8 +38,8 @@ class Primary { bg: "primary", transition: "opacity 300ms linear", ":hover": { - opacity: 0.8 - } + opacity: 0.8, + }, }; } } @@ -56,7 +57,7 @@ class Tertiary { color: "text", bg: "transparent", border: "2px solid", - borderColor: "border" + borderColor: "border", }; } } @@ -69,7 +70,7 @@ class List { borderBottom: "1px solid", borderBottomColor: "border", borderRadius: 0, - p: 2 + p: 2, }; } } @@ -81,7 +82,7 @@ class Anchor { color: "primary", fontSize: "subBody", p: 0, - m: 0 + m: 0, }; } } @@ -93,8 +94,8 @@ class Icon { color: "text", borderRadius: "none", ":hover": { - backgroundColor: "shade" - } + backgroundColor: "shade", + }, }; } } @@ -107,8 +108,8 @@ class Menu { p: 2, borderRadius: "none", ":hover": { - backgroundColor: "shade" - } + backgroundColor: "shade", + }, }; } } From b468dc076341addd2a56c53aadfd6cfc4e8e7186 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 12:39:39 +0500 Subject: [PATCH 377/394] navigation: persist history as well previously we were only persisting the last route but this caused the back button to disappear when the page was refreshed. Hence, I have added history persistence as well. This can probably be optimized a little bit more. Known Issue: JSON.stringify doesn't preserve the route component so we have to retrieve it manually using `this.getRoute(key).component`. --- apps/web/src/navigation/index.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/web/src/navigation/index.js b/apps/web/src/navigation/index.js index 0be43a826..8607d5637 100644 --- a/apps/web/src/navigation/index.js +++ b/apps/web/src/navigation/index.js @@ -16,8 +16,12 @@ class Navigator { } onLoad = () => { - const route = Config.get(this.root, this.getRoute(this.options.default)); - this.navigate(route.key, route.params, true); + const opts = Config.get(this.root, { + history: [], + lastRoute: this.getRoute(this.options.default), + }); + this.history = opts.history; + this.navigate(opts.lastRoute.key, opts.lastRoute.params, true); }; getRoute(key) { @@ -30,7 +34,10 @@ class Navigator { // NOTE: we delete the navigator key if any so it's always new across refreshes const copy = { ...route, params: { ...route.params } }; if (copy.params.navigator) delete copy.params.navigator; - Config.set(this.root, copy); + Config.set(this.root, { + history: this.history, + lastRoute: copy, + }); } getRoot() { @@ -89,9 +96,9 @@ class Navigator { goBack(params = {}) { let route = this.history.pop(); - if (!route) { - return false; - } + if (!route) return false; + if (!route.component) route.component = this.getRoute(route.key).component; + this.setLastRoute(route); return this.renderRoute(this._mergeParams(route, params)); } From 6c094a43ab8b77e60b607efb1971d4eef3af2dc9 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 12:51:59 +0500 Subject: [PATCH 378/394] feat: lazy load all routes --- apps/web/src/navigation/route.js | 6 ++++-- apps/web/src/views/index.js | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js index 8f1342dae..2f26492c3 100644 --- a/apps/web/src/navigation/route.js +++ b/apps/web/src/navigation/route.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { Suspense } from "react"; import { Box, Flex, Heading, Text } from "rebass"; import * as Icon from "../components/icons"; import ThemeProvider from "../components/theme-provider"; @@ -94,7 +94,9 @@ function Route(props) { )} {props.route.component && ( - + Loading...}> + + )} ); diff --git a/apps/web/src/views/index.js b/apps/web/src/views/index.js index 54a0ad7cd..79de587f6 100644 --- a/apps/web/src/views/index.js +++ b/apps/web/src/views/index.js @@ -1,9 +1,11 @@ -export const Home = require("./Home").default; -export const Notebooks = require("./Notebooks").default; -export const Notes = require("./Notes").default; -export const Topics = require("./Topics").default; -export const Settings = require("./Settings").default; -export const Trash = require("./Trash").default; -export const Account = require("./Account").default; -export const Tags = require("./Tags").default; -export const Search = require("./Search").default; +import { lazy } from "react"; + +export const Home = lazy(() => import("./Home")); +export const Notebooks = lazy(() => import("./Notebooks")); +export const Notes = lazy(() => import("./Notes")); +export const Topics = lazy(() => import("./Topics")); +export const Settings = lazy(() => import("./Settings")); +export const Trash = lazy(() => import("./Trash")); +export const Account = lazy(() => import("./Account")); +export const Tags = lazy(() => import("./Tags")); +export const Search = lazy(() => import("./Search")); From a5702648d323a6e181413c91e4ca1876a0a7c42a Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 13:03:13 +0500 Subject: [PATCH 379/394] ui: show nothing in Suspense fallback In my opinion blank is better than "Loading..." when navigating. Maybe we can rotate a spinner or something but I guess, blank is most lightweight for now. --- apps/web/src/navigation/route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js index 2f26492c3..5fd0e7f0d 100644 --- a/apps/web/src/navigation/route.js +++ b/apps/web/src/navigation/route.js @@ -94,7 +94,7 @@ function Route(props) { )} {props.route.component && ( - Loading...}> + }> )} From 6fad89bc215c762779e9e19416e3093eba4f95e3 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 13:07:57 +0500 Subject: [PATCH 380/394] ci: install babel-loader v8.1.0 dependency The ZEIT deployment fails if we do not specify a babel-loader explicitly --- apps/web/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/package.json b/apps/web/package.json index 8b118855b..674385781 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -27,6 +27,7 @@ "zustand": "^2.2.3" }, "devDependencies": { + "babel-loader": "8.1.0", "babel-eslint": "^10.1.0", "eslint": "^6.8.0", "eslint-config-react-app": "^5.2.1", From 32a68d69c9f9bfa31214a2b54d6d327a33ff6172 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 20 Apr 2020 13:30:23 +0500 Subject: [PATCH 381/394] Revert "feat: lazy load all routes" This reverts commit 6c094a43ab8b77e60b607efb1971d4eef3af2dc9. Because Suspense doesn't work that well with persistence. Don't know why. And besides, it gives a bad user experience. --- apps/web/src/navigation/route.js | 6 ++---- apps/web/src/views/index.js | 20 +++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js index 5fd0e7f0d..8f1342dae 100644 --- a/apps/web/src/navigation/route.js +++ b/apps/web/src/navigation/route.js @@ -1,4 +1,4 @@ -import React, { Suspense } from "react"; +import React from "react"; import { Box, Flex, Heading, Text } from "rebass"; import * as Icon from "../components/icons"; import ThemeProvider from "../components/theme-provider"; @@ -94,9 +94,7 @@ function Route(props) { )} {props.route.component && ( - }> - - + )} ); diff --git a/apps/web/src/views/index.js b/apps/web/src/views/index.js index 79de587f6..54a0ad7cd 100644 --- a/apps/web/src/views/index.js +++ b/apps/web/src/views/index.js @@ -1,11 +1,9 @@ -import { lazy } from "react"; - -export const Home = lazy(() => import("./Home")); -export const Notebooks = lazy(() => import("./Notebooks")); -export const Notes = lazy(() => import("./Notes")); -export const Topics = lazy(() => import("./Topics")); -export const Settings = lazy(() => import("./Settings")); -export const Trash = lazy(() => import("./Trash")); -export const Account = lazy(() => import("./Account")); -export const Tags = lazy(() => import("./Tags")); -export const Search = lazy(() => import("./Search")); +export const Home = require("./Home").default; +export const Notebooks = require("./Notebooks").default; +export const Notes = require("./Notes").default; +export const Topics = require("./Topics").default; +export const Settings = require("./Settings").default; +export const Trash = require("./Trash").default; +export const Account = require("./Account").default; +export const Tags = require("./Tags").default; +export const Search = require("./Search").default; From 42dcfc4ad474e5ced631980e7330f5e950322300 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 10:56:43 +0500 Subject: [PATCH 382/394] ui: increase menu width --- apps/web/src/components/menu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/menu/index.js b/apps/web/src/components/menu/index.js index d92237663..67887166c 100644 --- a/apps/web/src/components/menu/index.js +++ b/apps/web/src/components/menu/index.js @@ -13,7 +13,7 @@ function Menu(props) { borderRadius: "default", border: "2px solid", borderColor: "border", - width: 140, + width: 180, ...props.sx, }} > From 0040fd5650624bbe2cab81c14af690c78a806c84 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:18:55 +0500 Subject: [PATCH 383/394] fix: multi select causing crash --- apps/web/src/common/selectionoptions.js | 45 ++++++++++++------- .../src/components/list-container/index.js | 1 + apps/web/src/components/list-item/index.js | 8 ++-- apps/web/src/navigation/route.js | 42 +++++++++-------- apps/web/src/stores/selection-store.js | 8 ++-- 5 files changed, 62 insertions(+), 42 deletions(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index d25b8d7c3..05a20a5c7 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -8,8 +8,9 @@ import { db } from "./index"; import { showMoveNoteDialog } from "../components/dialogs/movenotedialog"; import { confirm } from "../components/dialogs/confirm"; -function createOption(icon, onClick) { +function createOption(key, icon, onClick) { return { + key, icon, onClick: async () => { await onClick.call(this, selectionStore); @@ -22,7 +23,9 @@ function createOptions(options = []) { return [...options, DeleteOption]; } -const DeleteOption = createOption(Icon.Trash, async function (state) { +const DeleteOption = createOption("deleteOption", Icon.Trash, async function ( + state +) { if ( !(await confirm(Icon.Trash, "Delete", "Are you sure you want to proceed?")) ) @@ -52,7 +55,9 @@ const DeleteOption = createOption(Icon.Trash, async function (state) { } }); -const FavoriteOption = createOption(Icon.Star, function (state) { +const FavoriteOption = createOption("favoriteOption", Icon.Star, function ( + state +) { // we know only notes can be favorited state.selectedItems.forEach(async (item) => { if (item.favorite) return; @@ -61,7 +66,9 @@ const FavoriteOption = createOption(Icon.Star, function (state) { notesStore.refresh(); }); -const UnfavoriteOption = createOption(Icon.Star, function (state) { +const UnfavoriteOption = createOption("unfavoriteOption", Icon.Star, function ( + state +) { // we know only notes can be favorited state.selectedItems.forEach(async (item) => { if (!item.favorite) return; @@ -70,19 +77,27 @@ const UnfavoriteOption = createOption(Icon.Star, function (state) { notesStore.setContext({ type: "favorites" }); }); -const AddToNotebookOption = createOption(Icon.Plus, async function (state) { - const items = state.selectedItems.map((item) => item.id); - if (await showMoveNoteDialog(items)) { - //TODO show proper snack - console.log("Notes moved successfully!"); +const AddToNotebookOption = createOption( + "atnOption", + Icon.Plus, + async function (state) { + const items = state.selectedItems.map((item) => item.id); + if (await showMoveNoteDialog(items)) { + //TODO show proper snack + console.log("Notes moved successfully!"); + } } -}); +); -const RestoreOption = createOption(Icon.Restore, async function (state) { - const items = state.selectedItems.map((item) => item.id); - await db.trash.restore(...items); - trashStore.refresh(); -}); +const RestoreOption = createOption( + "restoreOption", + Icon.Restore, + async function (state) { + const items = state.selectedItems.map((item) => item.id); + await db.trash.restore(...items); + trashStore.refresh(); + } +); const NotesOptions = createOptions([AddToNotebookOption, FavoriteOption]); const NotebooksOptions = createOptions(); diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 1a2533c3b..729dd820a 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -15,6 +15,7 @@ function ListContainer(props) { useEffect(() => { if (shouldSelectAll) setSelectedItems(props.items); }, [shouldSelectAll, setSelectedItems, props.items]); + useEffect(() => { if (props.noSearch) return; setSearchContext({ diff --git a/apps/web/src/components/list-item/index.js b/apps/web/src/components/list-item/index.js index 2c0e55749..786a9db4c 100644 --- a/apps/web/src/components/list-item/index.js +++ b/apps/web/src/components/list-item/index.js @@ -4,7 +4,7 @@ import { Flex, Box, Text } from "rebass"; import * as Icon from "../icons"; import Menu from "../menu"; import { - store as appStore, + store as selectionStore, useStore as useSelectionStore, } from "../../stores/selection-store"; import useContextMenu from "../../utils/useContextMenu"; @@ -13,9 +13,9 @@ function selectMenuItem(isSelected, toggleSelection) { return { title: isSelected ? "Unselect" : "Select", onClick: () => { - const appState = appStore; - if (!appState.isSelectionMode) { - appState.enterSelectionMode(); + const selectionState = selectionStore.get(); + if (!selectionState.isSelectionMode) { + selectionState.toggleSelectionMode(); toggleSelection(); } else { toggleSelection(); diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js index 8f1342dae..82ba5c1d1 100644 --- a/apps/web/src/navigation/route.js +++ b/apps/web/src/navigation/route.js @@ -3,12 +3,16 @@ import { Box, Flex, Heading, Text } from "rebass"; import * as Icon from "../components/icons"; import ThemeProvider from "../components/theme-provider"; import { useStore } from "../stores/app-store"; +import { useStore as useSelectionStore } from "../stores/selection-store"; function Route(props) { const toggleSideMenu = useStore((store) => store.toggleSideMenu); - const isSelectionMode = useStore((store) => store.isSelectionMode); - const exitSelectionMode = useStore((store) => store.exitSelectionMode); - const selectAll = useStore((store) => store.selectAll); + const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); + const toggleSelectionMode = useSelectionStore( + (store) => store.toggleSelectionMode + ); + const selectAll = useSelectionStore((store) => store.selectAll); + const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll); const navigator = props.params.navigator || props.navigator; return ( @@ -48,7 +52,7 @@ function Route(props) { {props.route.options.map((option) => ( )} {isSelectionMode && ( - - selectAll()} - > - Select all - - exitSelectionMode()} - > - Unselect + { + if (shouldSelectAll) { + toggleSelectionMode(false); + } else { + selectAll(); + } + }} + > + {shouldSelectAll ? : } + + {shouldSelectAll ? "Unselect" : "Select all"} )} diff --git a/apps/web/src/stores/selection-store.js b/apps/web/src/stores/selection-store.js index 4bedaef05..476cf7576 100644 --- a/apps/web/src/stores/selection-store.js +++ b/apps/web/src/stores/selection-store.js @@ -30,14 +30,14 @@ class SelectionStore extends BaseStore { } }; - setSelectedItems(items) { + setSelectedItems = (items) => { this.set((state) => (state.selectedItems = items)); - } + }; - selectAll() { + selectAll = () => { if (!this.get().isSelectionMode) return; this.set((state) => (state.shouldSelectAll = true)); - } + }; } /** From 5aca5adb0b02a9514596df78756dcfea47a4c800 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:36:09 +0500 Subject: [PATCH 384/394] feat: fragment route component into smaller components This improves rendering performance especially during selection mode toggling. --- apps/web/src/navigation/route.js | 189 +++++++++++++++++-------------- 1 file changed, 103 insertions(+), 86 deletions(-) diff --git a/apps/web/src/navigation/route.js b/apps/web/src/navigation/route.js index 82ba5c1d1..83366fa23 100644 --- a/apps/web/src/navigation/route.js +++ b/apps/web/src/navigation/route.js @@ -6,96 +6,12 @@ import { useStore } from "../stores/app-store"; import { useStore as useSelectionStore } from "../stores/selection-store"; function Route(props) { - const toggleSideMenu = useStore((store) => store.toggleSideMenu); - const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); - const toggleSelectionMode = useSelectionStore( - (store) => store.toggleSelectionMode - ); - const selectAll = useSelectionStore((store) => store.selectAll); - const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll); const navigator = props.params.navigator || props.navigator; + return ( - {(props.route.title || props.route.params.title) && ( - <> - - - {props.canGoBack && ( - - - - )} - - - - - {props.route.title || props.route.params.title} - - - {props.route.options && isSelectionMode && ( - - {props.route.options.map((option) => ( - - - - ))} - - )} - - {props.route.params.subtitle && ( - - {props.route.params.subtitle} - - )} - {isSelectionMode && ( - { - if (shouldSelectAll) { - toggleSelectionMode(false); - } else { - selectAll(); - } - }} - > - {shouldSelectAll ? : } - - {shouldSelectAll ? "Unselect" : "Select all"} - - - )} - - )} +
{props.route.component && ( @@ -104,3 +20,104 @@ function Route(props) { ); } export default Route; + +function Header(props) { + const { route, canGoBack, backAction } = props; + const { title, titleColor, params, options } = route; + + const toggleSideMenu = useStore((store) => store.toggleSideMenu); + + if (!title && !params.title) return null; + return ( + <> + + + {canGoBack && ( + + + + )} + + + + + {title || params.title} + + + + + {params.subtitle && ( + + {params.subtitle} + + )} + + + ); +} + +function SelectionOptions(props) { + const { options } = props; + + const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); + + if (!isSelectionMode || !options) return null; + return ( + + {options.map((option) => ( + + + + ))} + + ); +} + +function SelectionBox() { + const toggleSelectionMode = useSelectionStore( + (store) => store.toggleSelectionMode + ); + const selectAll = useSelectionStore((store) => store.selectAll); + const shouldSelectAll = useSelectionStore((store) => store.shouldSelectAll); + const isSelectionMode = useSelectionStore((store) => store.isSelectionMode); + + if (!isSelectionMode) return null; + return ( + { + if (shouldSelectAll) { + toggleSelectionMode(false); + } else { + selectAll(); + } + }} + > + {shouldSelectAll ? : } + + {shouldSelectAll ? "Unselect all" : "Select all"} + + + ); +} From 848def410496b7097041ecdedfd73a702225c09b Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:43:40 +0500 Subject: [PATCH 385/394] ui: fix text font sizes --- apps/web/src/components/properties/index.js | 2 +- apps/web/src/components/properties/toggle.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/properties/index.js b/apps/web/src/components/properties/index.js index 665c5654f..1ee923887 100644 --- a/apps/web/src/components/properties/index.js +++ b/apps/web/src/components/properties/index.js @@ -118,7 +118,7 @@ function Properties() { > - + {toTitleCase(label)} diff --git a/apps/web/src/components/properties/toggle.js b/apps/web/src/components/properties/toggle.js index 4c01c08f4..10161ddc9 100644 --- a/apps/web/src/components/properties/toggle.js +++ b/apps/web/src/components/properties/toggle.js @@ -15,7 +15,7 @@ function Toggle(props) { onClick={() => onToggle(!isOn)} > {isOn ? : } - + {label} From 8a9e83fc6b61d94891b037ebf993909369fa1996 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:46:22 +0500 Subject: [PATCH 386/394] fix: save opened note id in local storage --- apps/web/src/stores/editor-store.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/web/src/stores/editor-store.js b/apps/web/src/stores/editor-store.js index c52341940..60bcdd952 100644 --- a/apps/web/src/stores/editor-store.js +++ b/apps/web/src/stores/editor-store.js @@ -71,6 +71,9 @@ class EditorStore extends BaseStore { }; }); noteStore.setSelectedNote(note.id); + + if (note.locked) return; + saveLastOpenedNote(note.id); }; saveSession = (oldSession) => { From b40d1a4440f77cf7ac21ca5ccc6437cbb0df4518 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:52:11 +0500 Subject: [PATCH 387/394] ui: fix topic labels on notebook foreground These appeared black on blue when they should be white on blue. We use `static` color for it as it remains the same in all themes. --- apps/web/src/components/dialogs/topicdialog.js | 2 +- apps/web/src/components/notebook/index.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/dialogs/topicdialog.js b/apps/web/src/components/dialogs/topicdialog.js index b85365830..f7d106341 100644 --- a/apps/web/src/components/dialogs/topicdialog.js +++ b/apps/web/src/components/dialogs/topicdialog.js @@ -21,7 +21,7 @@ function TopicDialog(props) { > { setTopic(e.target.value); }} diff --git a/apps/web/src/components/notebook/index.js b/apps/web/src/components/notebook/index.js index 72e9a50a6..f5fa450f0 100644 --- a/apps/web/src/components/notebook/index.js +++ b/apps/web/src/components/notebook/index.js @@ -57,11 +57,11 @@ class Notebook extends React.Component { marginRight: 1, borderRadius: "default", color: "static", - paddingTop: 0.4, - paddingBottom: 0.4, + paddingTop: "2px", + paddingBottom: "2px", }} > - + {topic.title} From 1807afaa0f6a68d41ecfb492716895f12c8beea9 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 11:54:12 +0500 Subject: [PATCH 388/394] fix: send proper context when opening topic from topic label on notebooks --- apps/web/src/views/Notebooks.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/web/src/views/Notebooks.js b/apps/web/src/views/Notebooks.js index d8385084b..a1a3a5d0c 100644 --- a/apps/web/src/views/Notebooks.js +++ b/apps/web/src/views/Notebooks.js @@ -31,11 +31,9 @@ function Notebooks(props) { props.navigator.navigate("notes", { title: notebook.title, subtitle: topic.title, - notes: db.notebooks - .notebook(notebook.id) - .topics.topic(topic.title).all, context: { - notebook: { id: notebook.id, topic: topic.title }, + type: "topic", + value: { id: notebook.id, topic: topic.title }, }, }) } From 84ba34955d2fdd2bd17c33e8a703ae04ef8e2be5 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 12:00:06 +0500 Subject: [PATCH 389/394] refactor: formatting and some other stuff --- apps/web/src/components/dialogs/confirm.js | 8 +++++--- apps/web/src/views/Home.js | 1 + apps/web/src/views/Notebooks.js | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/dialogs/confirm.js b/apps/web/src/components/dialogs/confirm.js index 2b0ff12a9..5e66a7a0c 100644 --- a/apps/web/src/components/dialogs/confirm.js +++ b/apps/web/src/components/dialogs/confirm.js @@ -10,19 +10,21 @@ function Confirm(props) { icon={props.icon} positiveButton={{ text: "Yes", - onClick: props.onYes + onClick: props.onYes, }} negativeButton={{ text: "No", onClick: props.onNo }} > - {props.message} + + {props.message} +
); } export function confirm(icon, title, message) { - return showDialog(perform => ( + return showDialog((perform) => ( store.refresh(), []); const notes = useStore((store) => store.notes); const newSession = useEditorStore((store) => store.newSession); + return ( Date: Tue, 21 Apr 2020 12:01:15 +0500 Subject: [PATCH 390/394] hotfix: crash when moving an item to trash This should probably be investigated more and fixed properly. Seems like a core issue to me. --- apps/web/src/components/note/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index de209523f..853eba560 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -162,6 +162,8 @@ function Note(props) { export default React.memo(Note, function (prevProps, nextProps) { const prevItem = prevProps.item; const nextItem = nextProps.item; + // TODO need to investigate why a crash happens here. + if (!prevItem || !nextItem) return true; return ( prevItem.pinned === nextItem.pinned && prevItem.favorite === nextItem.favorite && From 7c00a281e4f88d9aa6d39d8fb1b2035326616351 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 12:33:29 +0500 Subject: [PATCH 391/394] chore: update notesnook-core --- apps/web/package.json | 2 +- apps/web/src/components/note/index.js | 3 ++- apps/web/yarn.lock | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 674385781..6487443b8 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -27,8 +27,8 @@ "zustand": "^2.2.3" }, "devDependencies": { - "babel-loader": "8.1.0", "babel-eslint": "^10.1.0", + "babel-loader": "8.1.0", "eslint": "^6.8.0", "eslint-config-react-app": "^5.2.1", "eslint-plugin-import": "^2.20.2", diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index 853eba560..fec23c352 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -162,7 +162,8 @@ function Note(props) { export default React.memo(Note, function (prevProps, nextProps) { const prevItem = prevProps.item; const nextItem = nextProps.item; - // TODO need to investigate why a crash happens here. + + // do not update if the item was removed if (!prevItem || !nextItem) return true; return ( prevItem.pinned === nextItem.pinned && diff --git a/apps/web/yarn.lock b/apps/web/yarn.lock index 82623ee24..b31517fe7 100644 --- a/apps/web/yarn.lock +++ b/apps/web/yarn.lock @@ -7291,9 +7291,9 @@ normalize-url@^3.0.0, normalize-url@^3.0.1: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== -"notes-core@https://github.com/streetwriters/notesnook-core.git": +"notes-core@git+ssh://git@github.com:streetwriters/notesnook-core.git": version "1.3.0" - resolved "https://github.com/streetwriters/notesnook-core.git#ed5ead55bed5ff5ec976ed46dc517854b407aff7" + resolved "git+ssh://git@github.com:streetwriters/notesnook-core.git#f1d3ccc200f76208b072414c1dc61f2bc3f148a9" dependencies: fast-sort "^2.0.1" fuzzysearch "^1.0.3" From c9866fe6c7ec6f628d50cb0650706dc17acfa45d Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 12:42:58 +0500 Subject: [PATCH 392/394] fix: crash when an item was removed from Virtuouso This was a pesky bug. Basically the `props.items.length` did not get updated which resulted in the `index` being always one greater than actual. Since `index[out-of-range]` is `undefined` in JS, the app crashed as it could not find any prop. Very pesky. Fixed it however. --- apps/web/src/components/list-container/index.js | 6 +++++- apps/web/src/components/note/index.js | 2 -- apps/web/src/views/Home.js | 9 +++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/web/src/components/list-container/index.js b/apps/web/src/components/list-container/index.js index 729dd820a..c23dff686 100644 --- a/apps/web/src/components/list-container/index.js +++ b/apps/web/src/components/list-container/index.js @@ -44,7 +44,11 @@ function ListContainer(props) { overflowX: "hidden", }} totalCount={props.items.length} - item={(index) => props.item(index, props.items[index])} + item={(index) => { + const item = props.items[index]; + if (!item) return null; + return props.item(index, item); + }} /> ) : null}
diff --git a/apps/web/src/components/note/index.js b/apps/web/src/components/note/index.js index fec23c352..cff0b6e2a 100644 --- a/apps/web/src/components/note/index.js +++ b/apps/web/src/components/note/index.js @@ -163,8 +163,6 @@ export default React.memo(Note, function (prevProps, nextProps) { const prevItem = prevProps.item; const nextItem = nextProps.item; - // do not update if the item was removed - if (!prevItem || !nextItem) return true; return ( prevItem.pinned === nextItem.pinned && prevItem.favorite === nextItem.favorite && diff --git a/apps/web/src/views/Home.js b/apps/web/src/views/Home.js index e279281ed..4a0f5cccc 100644 --- a/apps/web/src/views/Home.js +++ b/apps/web/src/views/Home.js @@ -42,11 +42,12 @@ function Home() { ); }} - item={(index, groupIndex) => - notes.groupCounts[groupIndex] && ( + item={(index, groupIndex) => { + if (!notes.groupCounts[groupIndex] || !notes.items[index]) return; + return ( - ) - } + ); + }} />
); From 78f0d6e0ce27225de3786d7c6aa7927441dcda18 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 12:52:44 +0500 Subject: [PATCH 393/394] fix: multi items move to trash --- apps/web/src/common/selectionoptions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 05a20a5c7..5be8f7a96 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -13,7 +13,7 @@ function createOption(key, icon, onClick) { key, icon, onClick: async () => { - await onClick.call(this, selectionStore); + await onClick.call(this, selectionStore.get()); selectionStore.toggleSelectionMode(false); }, }; From deaecda5027a44cc0018b9824b1b41b60ac19df1 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Tue, 21 Apr 2020 13:03:25 +0500 Subject: [PATCH 394/394] feat: impl permanent delete in multi select trash --- apps/web/src/common/selectionoptions.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/web/src/common/selectionoptions.js b/apps/web/src/common/selectionoptions.js index 5be8f7a96..2e2a1c656 100644 --- a/apps/web/src/common/selectionoptions.js +++ b/apps/web/src/common/selectionoptions.js @@ -31,6 +31,7 @@ const DeleteOption = createOption("deleteOption", Icon.Trash, async function ( ) return; const item = state.selectedItems[0]; + var isAnyNoteOpened = false; const items = state.selectedItems.map((item) => { if (item.id === editorStore.get().session.id) isAnyNoteOpened = true; @@ -38,6 +39,13 @@ const DeleteOption = createOption("deleteOption", Icon.Trash, async function ( return item.id; }); + if (item.dateDeleted) { + // we are in trash + await db.trash.delete(...items); + trashStore.refresh(); + return; + } + if (isAnyNoteOpened) { editorStore.newSession(); }