mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 14:39:34 +01:00
feat: improve UI of all dialogs
This commit is contained in:
@@ -6,7 +6,7 @@ import { store as editorStore } from "../stores/editor-store";
|
|||||||
import { store as trashStore } from "../stores/trash-store";
|
import { store as trashStore } from "../stores/trash-store";
|
||||||
import { db } from "./index";
|
import { db } from "./index";
|
||||||
import { showMoveNoteDialog } from "../components/dialogs/movenotedialog";
|
import { showMoveNoteDialog } from "../components/dialogs/movenotedialog";
|
||||||
import { confirm } from "../components/dialogs/confirm";
|
import { confirm, showDeleteConfirmation } from "../components/dialogs/confirm";
|
||||||
|
|
||||||
function createOption(key, icon, onClick) {
|
function createOption(key, icon, onClick) {
|
||||||
return {
|
return {
|
||||||
@@ -26,12 +26,10 @@ function createOptions(options = []) {
|
|||||||
const DeleteOption = createOption("deleteOption", Icon.Trash, async function (
|
const DeleteOption = createOption("deleteOption", Icon.Trash, async function (
|
||||||
state
|
state
|
||||||
) {
|
) {
|
||||||
if (
|
|
||||||
!(await confirm(Icon.Trash, "Delete", "Are you sure you want to proceed?"))
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
const item = state.selectedItems[0];
|
const item = state.selectedItems[0];
|
||||||
|
|
||||||
|
if (!(await showDeleteConfirmation(item.type, true))) return;
|
||||||
|
|
||||||
var isAnyNoteOpened = false;
|
var isAnyNoteOpened = false;
|
||||||
const items = state.selectedItems.map((item) => {
|
const items = state.selectedItems.map((item) => {
|
||||||
if (item.id === editorStore.get().session.id) isAnyNoteOpened = true;
|
if (item.id === editorStore.get().session.id) isAnyNoteOpened = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Flex, Box, Text, Button as RebassButton } from "rebass";
|
import { Flex, Box, Button as RebassButton } from "rebass";
|
||||||
import { Input } from "@rebass/forms";
|
import { Input } from "@rebass/forms";
|
||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import Dialog, { showDialog } from "./dialog";
|
import Dialog, { showDialog } from "./dialog";
|
||||||
@@ -86,10 +86,13 @@ class AddNotebookDialog extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={props.isOpen}
|
isOpen={props.isOpen}
|
||||||
title="Notebook"
|
title={props.edit ? "Edit this Notebook" : "Create a Notebook"}
|
||||||
|
description={
|
||||||
|
props.edit ? "" : "Notebooks are the best way to organize your notes."
|
||||||
|
}
|
||||||
icon={Icon.Notebook}
|
icon={Icon.Notebook}
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: props.edit ? "Edit" : "Add",
|
text: "Create notebook",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
props.onDone({
|
props.onDone({
|
||||||
title: this.title,
|
title: this.title,
|
||||||
@@ -104,7 +107,7 @@ class AddNotebookDialog extends React.Component {
|
|||||||
}}
|
}}
|
||||||
negativeButton={{ text: "Cancel", onClick: props.close }}
|
negativeButton={{ text: "Cancel", onClick: props.close }}
|
||||||
>
|
>
|
||||||
<Box my={1}>
|
<Box>
|
||||||
<Input
|
<Input
|
||||||
autoFocus
|
autoFocus
|
||||||
onChange={(e) => (this.title = e.target.value)}
|
onChange={(e) => (this.title = e.target.value)}
|
||||||
@@ -112,19 +115,16 @@ class AddNotebookDialog extends React.Component {
|
|||||||
defaultValue={this.title}
|
defaultValue={this.title}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
sx={{ marginTop: 1 }}
|
sx={{ marginTop: 2 }}
|
||||||
onChange={(e) => (this.description = e.target.value)}
|
onChange={(e) => (this.description = e.target.value)}
|
||||||
placeholder="Enter description (optional)"
|
placeholder="Enter description (optional)"
|
||||||
defaultValue={this.description}
|
defaultValue={this.description}
|
||||||
/>
|
/>
|
||||||
<Text variant="body" fontWeight="bold" my={1}>
|
|
||||||
Topics (optional):
|
|
||||||
</Text>
|
|
||||||
<Box
|
<Box
|
||||||
|
mt={2}
|
||||||
sx={{
|
sx={{
|
||||||
maxHeight: this.MAX_AVAILABLE_HEIGHT,
|
maxHeight: this.MAX_AVAILABLE_HEIGHT,
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
marginBottom: 1,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{this.state.topics.map(
|
{this.state.topics.map(
|
||||||
@@ -164,7 +164,7 @@ class AddNotebookDialog extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<RebassButton
|
<RebassButton
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
sx={{ marginLeft: 1 }}
|
sx={{ marginLeft: 2 }}
|
||||||
px={2}
|
px={2}
|
||||||
py={1}
|
py={1}
|
||||||
onClick={() => this.performActionOnTopic(index)}
|
onClick={() => this.performActionOnTopic(index)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Box, Text } from "rebass";
|
import { Box, Text } from "rebass";
|
||||||
import Dialog, { showDialog } from "./dialog";
|
import Dialog, { showDialog } from "./dialog";
|
||||||
|
import * as Icon from "../icons";
|
||||||
|
|
||||||
function Confirm(props) {
|
function Confirm(props) {
|
||||||
return (
|
return (
|
||||||
@@ -8,14 +9,15 @@ function Confirm(props) {
|
|||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
|
description={props.subtitle}
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: "Yes",
|
text: props.yesText,
|
||||||
onClick: props.onYes,
|
onClick: props.onYes,
|
||||||
}}
|
}}
|
||||||
negativeButton={{ text: "No", onClick: props.onNo }}
|
negativeButton={{ text: props.noText, onClick: props.onNo }}
|
||||||
>
|
>
|
||||||
<Box my={1}>
|
<Box my={2}>
|
||||||
<Text textAlign="center" variant="body">
|
<Text as="span" variant="body" fontSize={18}>
|
||||||
{props.message}
|
{props.message}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -23,14 +25,67 @@ function Confirm(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function confirm(icon, title, message) {
|
export function confirm(icon, { title, subtitle, message, yesText, noText }) {
|
||||||
return showDialog((perform) => (
|
return showDialog((perform) => (
|
||||||
<Confirm
|
<Confirm
|
||||||
title={title}
|
title={title}
|
||||||
|
subtitle={subtitle}
|
||||||
message={message}
|
message={message}
|
||||||
|
yesText={yesText}
|
||||||
|
noText={noText}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
onNo={() => perform(false)}
|
onNo={() => perform(false)}
|
||||||
onYes={() => perform(true)}
|
onYes={() => perform(true)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {"note"|"notebook"} type
|
||||||
|
*/
|
||||||
|
export function showDeleteConfirmation(type, multi = false) {
|
||||||
|
let noun = type === "note" ? "Note" : "Notebook";
|
||||||
|
if (multi) noun += "s";
|
||||||
|
let lowerCaseNoun = noun.toLowerCase();
|
||||||
|
|
||||||
|
let [firstPronoun, secondPronoun] = multi
|
||||||
|
? ["these", "they"]
|
||||||
|
: ["this", "it"];
|
||||||
|
|
||||||
|
return confirm(Icon.Trash, {
|
||||||
|
title: `Delete ${noun}`,
|
||||||
|
subtitle: `Are you sure you want to delete ${firstPronoun} ${lowerCaseNoun}?`,
|
||||||
|
message: (
|
||||||
|
<Text as="span">
|
||||||
|
The {lowerCaseNoun} will be{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
kept in your Trash for 7 days
|
||||||
|
</Text>{" "}
|
||||||
|
after which {secondPronoun} will be permanently removed.
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
yesText: `Delete ${lowerCaseNoun}`,
|
||||||
|
noText: "Cancel",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showMultiDeleteConfirmation(type) {
|
||||||
|
let noun = type === "note" ? "Notes" : "Notebooks";
|
||||||
|
|
||||||
|
return confirm(Icon.Trash, {
|
||||||
|
title: `Delete these ${noun}`,
|
||||||
|
subtitle: `Are you sure you want to delete these ${type}s?`,
|
||||||
|
message: (
|
||||||
|
<Text as="span">
|
||||||
|
These {type}s will be{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
kept in your Trash for 7 days
|
||||||
|
</Text>{" "}
|
||||||
|
after which they will be permanently removed.
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
yesText: `Delete these ${type}s`,
|
||||||
|
noText: "Cancel",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import ThemeProvider from "../theme-provider";
|
|||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import Modal from "react-modal";
|
import Modal from "react-modal";
|
||||||
import useMobile from "../../utils/use-mobile";
|
import useMobile from "../../utils/use-mobile";
|
||||||
|
import { useTheme } from "emotion-theming";
|
||||||
|
|
||||||
function Dialog(props) {
|
function Dialog(props) {
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider>
|
|
||||||
{(theme) => (
|
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={props.isOpen || false}
|
isOpen={props.isOpen || false}
|
||||||
shouldCloseOnOverlayClick={true}
|
shouldCloseOnOverlayClick={true}
|
||||||
@@ -28,10 +28,9 @@ function Dialog(props) {
|
|||||||
borderRadius: theme.radii["default"],
|
borderRadius: theme.radii["default"],
|
||||||
backgroundColor: theme.colors.background,
|
backgroundColor: theme.colors.background,
|
||||||
color: theme.colors.text,
|
color: theme.colors.text,
|
||||||
//boxShadow: theme.shadows["3"],
|
boxShadow: "4px 5px 18px 2px #00000038",
|
||||||
width: isMobile ? "80%" : "25%",
|
width: isMobile ? "80%" : "30%",
|
||||||
paddingRight: 20,
|
padding: 0,
|
||||||
paddingLeft: 20,
|
|
||||||
overflowY: "hidden",
|
overflowY: "hidden",
|
||||||
},
|
},
|
||||||
overlay: {
|
overlay: {
|
||||||
@@ -40,21 +39,31 @@ function Dialog(props) {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Flex flexDirection="column">
|
<Flex p={30} flexDirection="column">
|
||||||
<Flex variant="rowCenter" pb={2}>
|
<Flex
|
||||||
|
variant="columnCenter"
|
||||||
|
pb={2}
|
||||||
|
mb={3}
|
||||||
|
sx={{ borderBottom: "1px solid", borderColor: "border" }}
|
||||||
|
>
|
||||||
<props.icon size={props.iconSize || 38} color="primary" />
|
<props.icon size={props.iconSize || 38} color="primary" />
|
||||||
<Text variant="heading" color="primary" mx={1}>
|
<Text variant="heading" textAlign="center" color="text" mx={1} mt={1}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text variant="body" textAlign="center" color="gray" mx={1} mt={1}>
|
||||||
|
{props.description}
|
||||||
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
{props.children}
|
{props.children}
|
||||||
<Flex variant="rowCenter" mt={3}>
|
<Flex
|
||||||
|
sx={{ justifyContent: props.buttonsAlignment || "flex-end" }}
|
||||||
|
mt={3}
|
||||||
|
>
|
||||||
{props.positiveButton && (
|
{props.positiveButton && (
|
||||||
<RebassButton
|
<RebassButton
|
||||||
variant="primary"
|
variant="primary"
|
||||||
sx={{ opacity: props.positiveButton.disabled ? 0.7 : 1 }}
|
sx={{ opacity: props.positiveButton.disabled ? 0.7 : 1 }}
|
||||||
mx={1}
|
mx={1}
|
||||||
width={"50%"}
|
|
||||||
disabled={props.positiveButton.disabled || false}
|
disabled={props.positiveButton.disabled || false}
|
||||||
onClick={
|
onClick={
|
||||||
!props.positiveButton.disabled
|
!props.positiveButton.disabled
|
||||||
@@ -69,21 +78,18 @@ function Dialog(props) {
|
|||||||
)}
|
)}
|
||||||
</RebassButton>
|
</RebassButton>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{props.negativeButton && (
|
{props.negativeButton && (
|
||||||
<RebassButton
|
<RebassButton
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
width={"50%"}
|
|
||||||
onClick={props.negativeButton.onClick}
|
onClick={props.negativeButton.onClick}
|
||||||
>
|
>
|
||||||
{props.negativeButton.text || "Cancel"}
|
{props.negativeButton.text || "Cancel"}
|
||||||
</RebassButton>
|
</RebassButton>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
{props.footer}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
|
||||||
</ThemeProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default Dialog;
|
export default Dialog;
|
||||||
@@ -97,7 +103,7 @@ export function showDialog(dialog) {
|
|||||||
if (root) {
|
if (root) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const PropDialog = dialog(perform.bind(this, resolve));
|
const PropDialog = dialog(perform.bind(this, resolve));
|
||||||
ReactDOM.render(PropDialog, root);
|
ReactDOM.render(<ThemeProvider>{PropDialog}</ThemeProvider>, root);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.reject("No element with id 'dialogContainer'");
|
return Promise.reject("No element with id 'dialogContainer'");
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Flex, Button, Text, Box } from "rebass";
|
import { Flex, Button, Text } from "rebass";
|
||||||
import { db } from "../../common";
|
import { db } from "../../common";
|
||||||
import download from "../../utils/download";
|
import download from "../../utils/download";
|
||||||
import { showToast } from "../../utils/toast";
|
import { showToast } from "../../utils/toast";
|
||||||
@@ -12,38 +12,33 @@ function ExportDialog(props) {
|
|||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
negativeButton={{ onClick: props.onClose, text: "Cancel" }}
|
description="You can export your note to Markdown, HTML, or Text."
|
||||||
|
buttonsAlignment="center"
|
||||||
|
negativeButton={{
|
||||||
|
onClick: props.onClose,
|
||||||
|
text: "I don't want to export anymore",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Box>
|
<Flex justifyContent="center" alignItems="center">
|
||||||
<Text variant="body" mb={2}>
|
<Button mr={2} onClick={() => props.exportNote("html")}>
|
||||||
Please choose a format to export the note into:
|
<Flex variant="rowCenter">
|
||||||
</Text>
|
<Icon.HTML color="static" />
|
||||||
<Flex my={1} justifyContent="center" alignItems="center">
|
<Text ml={1}>HTML</Text>
|
||||||
<Button
|
</Flex>
|
||||||
variant="tertiary"
|
|
||||||
mr={2}
|
|
||||||
onClick={() => props.exportNote("html")}
|
|
||||||
>
|
|
||||||
<Icon.HTML size={100} color="dimPrimary" /> HTML
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button mr={2} onClick={() => props.exportNote("md")}>
|
||||||
variant="tertiary"
|
<Flex variant="rowCenter">
|
||||||
mr={2}
|
<Icon.Markdown color="static" />
|
||||||
onClick={() => props.exportNote("md")}
|
<Text ml={1}>Markdown</Text>
|
||||||
>
|
</Flex>
|
||||||
<Icon.Markdown size={100} color="dimPrimary" />
|
|
||||||
Markdown
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button mr={2} onClick={() => props.exportNote("txt")}>
|
||||||
variant="tertiary"
|
<Flex variant="rowCenter">
|
||||||
mr={2}
|
<Icon.Text color="static" />
|
||||||
onClick={() => props.exportNote("txt")}
|
<Text ml={1}>Text</Text>
|
||||||
>
|
</Flex>
|
||||||
<Icon.Text size={100} color="dimPrimary" />
|
|
||||||
Text
|
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -51,7 +46,7 @@ function ExportDialog(props) {
|
|||||||
export function showExportDialog(noteId) {
|
export function showExportDialog(noteId) {
|
||||||
return showDialog((perform) => (
|
return showDialog((perform) => (
|
||||||
<ExportDialog
|
<ExportDialog
|
||||||
title={"Export Note"}
|
title={"Export your Note"}
|
||||||
icon={Icon.Export}
|
icon={Icon.Export}
|
||||||
onClose={() => perform(false)}
|
onClose={() => perform(false)}
|
||||||
exportNote={async (format) => {
|
exportNote={async (format) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Box, Button, Text } from "rebass";
|
import { Flex, Button, Text } from "rebass";
|
||||||
import Input from "../inputs";
|
import Input from "../inputs";
|
||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import Dialog, { showDialog } from "./dialog";
|
import Dialog, { showDialog } from "./dialog";
|
||||||
@@ -18,19 +18,38 @@ function LoginDialog(props) {
|
|||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={"Login"}
|
title={"Sign in to Your Account"}
|
||||||
|
description={"Signing in allows you to sync your notes across devices."}
|
||||||
icon={Icon.Login}
|
icon={Icon.Login}
|
||||||
onCloseClick={onClose}
|
onCloseClick={onClose}
|
||||||
negativeButton={{ onClick: onClose }}
|
negativeButton={{ text: "I don't want to", onClick: onClose }}
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: "Login",
|
text: "Sign me in",
|
||||||
loading: isLoggingIn,
|
loading: isLoggingIn,
|
||||||
disabled: isLoggingIn,
|
disabled: isLoggingIn,
|
||||||
onClick: () => submit(setError, form, login, onClose),
|
onClick: () => submit(setError, form, login, onClose),
|
||||||
}}
|
}}
|
||||||
|
buttonsAlignment="center"
|
||||||
|
footer={
|
||||||
|
<>
|
||||||
|
<Text textAlign="center" color="gray" mt={3}>
|
||||||
|
Don't have an account?
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
mt={3}
|
||||||
|
variant="anchor"
|
||||||
|
justifySelf="center"
|
||||||
|
alignSelf="center"
|
||||||
|
fontSize="body"
|
||||||
|
onClick={showSignUpDialog}
|
||||||
>
|
>
|
||||||
<Box
|
Sign up here
|
||||||
mt={1}
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
variant="columnFill"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") submit(setError, form, login, onClose);
|
if (e.key === "Enter") submit(setError, form, login, onClose);
|
||||||
}}
|
}}
|
||||||
@@ -39,11 +58,11 @@ function LoginDialog(props) {
|
|||||||
<Input autoFocus name="username" title="Username" />
|
<Input autoFocus name="username" title="Username" />
|
||||||
<PasswordInput />
|
<PasswordInput />
|
||||||
</Dropper>
|
</Dropper>
|
||||||
<Button variant="anchor" onClick={showSignUpDialog}>
|
|
||||||
Create a New Account
|
|
||||||
</Button>
|
|
||||||
{error && <Text variant="error">{error}</Text>}
|
{error && <Text variant="error">{error}</Text>}
|
||||||
</Box>
|
{/* <Button variant="anchor" onClick={showSignUpDialog}>
|
||||||
|
I don't have an account
|
||||||
|
</Button> */}
|
||||||
|
</Flex>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Flex, Box, Text } from "rebass";
|
import { Flex, Box, Text, Button } from "rebass";
|
||||||
import { Input } from "@rebass/forms";
|
import { Input } from "@rebass/forms";
|
||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import { db } from "../../common";
|
import { db } from "../../common";
|
||||||
@@ -14,73 +14,32 @@ class MoveDialog extends React.Component {
|
|||||||
selectedNotebook;
|
selectedNotebook;
|
||||||
selectedTopic;
|
selectedTopic;
|
||||||
state = {
|
state = {
|
||||||
items: db.notebooks.all,
|
currentOpenedIndex: -1,
|
||||||
type: "notebooks",
|
notebooks: db.notebooks.all,
|
||||||
title: "Notebooks",
|
|
||||||
mode: "read",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { items, type, title, mode } = this.state;
|
const { notebooks, currentOpenedIndex } = this.state;
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={
|
title={"Add Note to Notebook"}
|
||||||
type === "notes"
|
description={"Organize your notes by adding them to notebooks."}
|
||||||
? "Move Note"
|
icon={Icon.Move}
|
||||||
: "Select " + toTitleCase(type.substring(0, type.length - 1))
|
buttonsAlignment="center"
|
||||||
}
|
negativeButton={{
|
||||||
icon={
|
text: "Get me out of here",
|
||||||
type === "notes"
|
onClick: props.onClose,
|
||||||
? Icon.Move
|
|
||||||
: type === "topics"
|
|
||||||
? Icon.Topic
|
|
||||||
: Icon.Notebook
|
|
||||||
}
|
|
||||||
positiveButton={{
|
|
||||||
text: "Move",
|
|
||||||
onClick: async () => {
|
|
||||||
try {
|
|
||||||
const notebook = {
|
|
||||||
id: this.selectedNotebook.id,
|
|
||||||
topic: this.selectedTopic,
|
|
||||||
};
|
|
||||||
const note = db.notes.note(props.noteIds[0]).data;
|
|
||||||
await db.notes.move(notebook, ...props.noteIds);
|
|
||||||
showNotesMovedToast(note, props.noteIds, notebook);
|
|
||||||
props.onMove();
|
|
||||||
} catch (e) {
|
|
||||||
showToast("error", e.message);
|
|
||||||
console.error(e);
|
|
||||||
} finally {
|
|
||||||
props.onClose();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disabled: type !== "notes",
|
|
||||||
}}
|
}}
|
||||||
negativeButton={{ text: "Cancel", onClick: props.onClose }}
|
|
||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Flex alignContent="center" justifyContent="space-between" my={1}>
|
<Flex alignItems="center" justifyContent="space-between" mb={2}>
|
||||||
<Flex>
|
<Text variant="title">Notebooks</Text>
|
||||||
<Text
|
<Button
|
||||||
onClick={() => {
|
variant="anchor"
|
||||||
let item = this.history.pop();
|
fontSize="body"
|
||||||
this.setState({ ...item });
|
/* onClick={() => {
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
display: this.history.length ? "block" : "none",
|
|
||||||
":hover": { color: "primary" },
|
|
||||||
marginRight: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon.ArrowLeft />
|
|
||||||
</Text>
|
|
||||||
<Text variant="title">{title}</Text>
|
|
||||||
</Flex>
|
|
||||||
<Text
|
|
||||||
onClick={() => {
|
|
||||||
if (mode === "write") {
|
if (mode === "write") {
|
||||||
this.setState({ mode: "read" });
|
this.setState({ mode: "read" });
|
||||||
return;
|
return;
|
||||||
@@ -89,16 +48,12 @@ class MoveDialog extends React.Component {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this._inputRef.focus();
|
this._inputRef.focus();
|
||||||
}, 0);
|
}, 0);
|
||||||
}}
|
}} */
|
||||||
sx={{
|
|
||||||
display: type === "notes" ? "none" : "block",
|
|
||||||
":hover": { color: "primary" },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{mode === "read" ? <Icon.Plus /> : <Icon.Minus />}
|
Create
|
||||||
</Text>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Input
|
{/* <Input
|
||||||
ref={(ref) => (this._inputRef = ref)}
|
ref={(ref) => (this._inputRef = ref)}
|
||||||
sx={{ display: mode === "write" ? "block" : "none" }}
|
sx={{ display: mode === "write" ? "block" : "none" }}
|
||||||
my={1}
|
my={1}
|
||||||
@@ -123,7 +78,7 @@ class MoveDialog extends React.Component {
|
|||||||
this.setState({ mode: "read" });
|
this.setState({ mode: "read" });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/> */}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
@@ -133,20 +88,11 @@ class MoveDialog extends React.Component {
|
|||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{items.length ? (
|
{notebooks.map((notebook, index) => (
|
||||||
items.map((item) => {
|
|
||||||
return (
|
|
||||||
<Flex
|
<Flex
|
||||||
key={item.title + item.dateCreated}
|
variant="columnFill"
|
||||||
sx={{
|
key={notebook.id}
|
||||||
borderWidth: 1,
|
/* onClick={() => {
|
||||||
padding: 2,
|
|
||||||
borderBottomColor: "border",
|
|
||||||
borderBottomStyle: "solid",
|
|
||||||
cursor: "pointer",
|
|
||||||
":hover": { borderBottomColor: "primary" },
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
this.history.push({
|
this.history.push({
|
||||||
title,
|
title,
|
||||||
items,
|
items,
|
||||||
@@ -169,31 +115,59 @@ class MoveDialog extends React.Component {
|
|||||||
});
|
});
|
||||||
this.selectedTopic = item.title;
|
this.selectedTopic = item.title;
|
||||||
}
|
}
|
||||||
|
}} */
|
||||||
|
>
|
||||||
|
<Item
|
||||||
|
icon={Icon.Notebook}
|
||||||
|
title={notebook.title}
|
||||||
|
totalNotes={notebook.totalNotes}
|
||||||
|
onClick={() =>
|
||||||
|
this.setState({
|
||||||
|
currentOpenedIndex:
|
||||||
|
this.state.currentOpenedIndex === index ? -1 : index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Flex
|
||||||
|
variant="columnFill"
|
||||||
|
style={{
|
||||||
|
display: currentOpenedIndex === index ? "flex" : "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text sx={{ width: "80%" }} fontSize="body">
|
{notebook.topics.map((topic) => (
|
||||||
{item.title}
|
<Item
|
||||||
|
key={topic.id}
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
const nb = {
|
||||||
|
id: notebook.id,
|
||||||
|
topic: topic.id,
|
||||||
|
};
|
||||||
|
const note = db.notes.note(props.noteIds[0]).data;
|
||||||
|
await db.notes.move(nb, ...props.noteIds);
|
||||||
|
showNotesMovedToast(note, props.noteIds, nb);
|
||||||
|
props.onMove();
|
||||||
|
} catch (e) {
|
||||||
|
showToast("error", e.message);
|
||||||
|
console.error(e);
|
||||||
|
} finally {
|
||||||
|
props.onClose();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
indent={1}
|
||||||
|
icon={Icon.Topic}
|
||||||
|
title={topic.title}
|
||||||
|
totalNotes={topic.totalNotes}
|
||||||
|
action={
|
||||||
|
<Text color="primary" fontSize="body">
|
||||||
|
Move here
|
||||||
</Text>
|
</Text>
|
||||||
{item.totalNotes !== undefined && (
|
}
|
||||||
<Text
|
/>
|
||||||
sx={{ width: "20%", textAlign: "right" }}
|
))}
|
||||||
fontSize="body"
|
|
||||||
>
|
|
||||||
{item.totalNotes + " Notes"}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
</Flex>
|
||||||
})
|
))}
|
||||||
) : (
|
|
||||||
<Text
|
|
||||||
py={2}
|
|
||||||
px={2}
|
|
||||||
sx={{ textAlign: "center", fontStyle: "italic" }}
|
|
||||||
>
|
|
||||||
Nothing here
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@@ -210,3 +184,35 @@ export function showMoveNoteDialog(noteIds) {
|
|||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Item(props) {
|
||||||
|
const { icon: Icon, indent = 0, title, totalNotes, onClick, action } = props;
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
p={2}
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
pl={!indent ? 2 : indent * 30}
|
||||||
|
sx={{
|
||||||
|
borderWidth: 1,
|
||||||
|
borderBottomColor: "border",
|
||||||
|
borderBottomStyle: "solid",
|
||||||
|
cursor: "pointer",
|
||||||
|
":hover": { borderBottomColor: "primary" },
|
||||||
|
}}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<Flex alignItems="center" justifyContent="center">
|
||||||
|
<Icon />
|
||||||
|
<Text as="span" ml={1} fontSize="body">
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
{action || (
|
||||||
|
<Text sx={{ textAlign: "right" }} fontSize="body">
|
||||||
|
{totalNotes + " Notes"}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ function PasswordDialog(props) {
|
|||||||
<Dialog
|
<Dialog
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
|
description={props.subtitle}
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: props.positiveButtonText,
|
text: props.positiveButtonText,
|
||||||
@@ -59,21 +60,24 @@ function getDialogData(type) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case "create_vault":
|
case "create_vault":
|
||||||
return {
|
return {
|
||||||
title: "Set Up Your Vault",
|
title: "Create Your Vault",
|
||||||
|
subtitle: "Your vault will encrypt everything locally.",
|
||||||
icon: Icon.Vault,
|
icon: Icon.Vault,
|
||||||
positiveButtonText: "Done",
|
positiveButtonText: "Create my vault",
|
||||||
};
|
};
|
||||||
case "unlock_vault":
|
case "unlock_vault":
|
||||||
return {
|
return {
|
||||||
title: "Unlock Vault",
|
title: "Unlock your Vault",
|
||||||
|
subtitle: "Your vault will remain unlocked for 30 minutes.",
|
||||||
icon: Icon.Unlock,
|
icon: Icon.Unlock,
|
||||||
positiveButtonText: "Unlock",
|
positiveButtonText: "Unlock my vault",
|
||||||
};
|
};
|
||||||
case "unlock_note":
|
case "unlock_note":
|
||||||
return {
|
return {
|
||||||
title: "Unlock Note",
|
title: "Unlock your Note",
|
||||||
|
subtitle: "Unlocking will make this note openly available.",
|
||||||
icon: Icon.Unlock,
|
icon: Icon.Unlock,
|
||||||
positiveButtonText: "Unlock",
|
positiveButtonText: "Unlock this note",
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@@ -81,10 +85,11 @@ function getDialogData(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function showPasswordDialog(type, validate) {
|
export function showPasswordDialog(type, validate) {
|
||||||
const { title, icon, positiveButtonText } = getDialogData(type);
|
const { title, subtitle, icon, positiveButtonText } = getDialogData(type);
|
||||||
return showDialog((perform) => (
|
return showDialog((perform) => (
|
||||||
<PasswordDialog
|
<PasswordDialog
|
||||||
title={title}
|
title={title}
|
||||||
|
subtitle={subtitle}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
positiveButtonText={positiveButtonText}
|
positiveButtonText={positiveButtonText}
|
||||||
onCancel={() => perform(false)}
|
onCancel={() => perform(false)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Text, Box } from "rebass";
|
import { Text, Box, Button } from "rebass";
|
||||||
import Input from "../inputs";
|
import Input from "../inputs";
|
||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import Dialog, { showDialog } from "./dialog";
|
import Dialog, { showDialog } from "./dialog";
|
||||||
@@ -8,6 +8,7 @@ import EmailInput from "../inputs/email";
|
|||||||
import PasswordInput from "../inputs/password";
|
import PasswordInput from "../inputs/password";
|
||||||
import Dropper from "../dropper";
|
import Dropper from "../dropper";
|
||||||
import { useStore } from "../../stores/user-store";
|
import { useStore } from "../../stores/user-store";
|
||||||
|
import { showLogInDialog } from "./logindialog";
|
||||||
|
|
||||||
const form = { error: true };
|
const form = { error: true };
|
||||||
function SignUpDialog(props) {
|
function SignUpDialog(props) {
|
||||||
@@ -19,19 +20,35 @@ function SignUpDialog(props) {
|
|||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={"Sign Up"}
|
title={"Create a new Account"}
|
||||||
icon={Icon.User}
|
description={"Sign up for a 14-day free trial (no credit card)."}
|
||||||
|
icon={Icon.Signup}
|
||||||
onCloseClick={onClose}
|
onCloseClick={onClose}
|
||||||
negativeButton={{ onClick: onClose }}
|
negativeButton={{ text: "I don't want to", onClick: onClose }}
|
||||||
|
buttonsAlignment="center"
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: "Sign Up",
|
text: "Create my account",
|
||||||
loading: isSigningIn,
|
loading: isSigningIn,
|
||||||
disabled: isSigningIn,
|
disabled: isSigningIn,
|
||||||
onClick: () => submit(setError, form, signup, onClose),
|
onClick: () => submit(setError, form, signup, onClose),
|
||||||
}}
|
}}
|
||||||
|
footer={
|
||||||
|
<>
|
||||||
|
<Text textAlign="center" color="gray" mt={3}>
|
||||||
|
Already have an account?
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
variant="anchor"
|
||||||
|
mt={2}
|
||||||
|
fontSize="body"
|
||||||
|
onClick={showLogInDialog}
|
||||||
|
>
|
||||||
|
Sign in here.
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
mt={1}
|
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === "Enter") submit(setError, form, signup, onClose);
|
if (e.key === "Enter") submit(setError, form, signup, onClose);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ function TopicDialog(props) {
|
|||||||
<Dialog
|
<Dialog
|
||||||
isOpen={true}
|
isOpen={true}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
|
description="You can create as many topics as you want."
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
positiveButton={{
|
positiveButton={{
|
||||||
text: "Add",
|
text: "Create topic",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
props.onYes(ref.current.value);
|
props.onYes(ref.current.value);
|
||||||
},
|
},
|
||||||
@@ -37,7 +38,7 @@ function TopicDialog(props) {
|
|||||||
export function showTopicDialog(notebook) {
|
export function showTopicDialog(notebook) {
|
||||||
return showDialog((perform) => (
|
return showDialog((perform) => (
|
||||||
<TopicDialog
|
<TopicDialog
|
||||||
title={"Topic"}
|
title={"Create a Topic"}
|
||||||
icon={Icon.Topic}
|
icon={Icon.Topic}
|
||||||
onNo={() => {
|
onNo={() => {
|
||||||
perform(false);
|
perform(false);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const Plus = createIcon(Icons.mdiPlus);
|
|||||||
export const Minus = createIcon(Icons.mdiMinus);
|
export const Minus = createIcon(Icons.mdiMinus);
|
||||||
export const Notebook = createIcon(Icons.mdiBookOutline);
|
export const Notebook = createIcon(Icons.mdiBookOutline);
|
||||||
export const ArrowLeft = createIcon(Icons.mdiArrowLeft);
|
export const ArrowLeft = createIcon(Icons.mdiArrowLeft);
|
||||||
export const Move = createIcon(Icons.mdiArrowAll);
|
export const Move = createIcon(Icons.mdiBookPlusMultipleOutline);
|
||||||
export const Topic = createIcon(Icons.mdiFormatTitle);
|
export const Topic = createIcon(Icons.mdiFormatTitle);
|
||||||
export const Alert = createIcon(Icons.mdiAlert);
|
export const Alert = createIcon(Icons.mdiAlert);
|
||||||
export const Vault = createIcon(Icons.mdiShieldOutline);
|
export const Vault = createIcon(Icons.mdiShieldOutline);
|
||||||
@@ -54,6 +54,7 @@ export const Trash = createIcon(Icons.mdiTrashCanOutline);
|
|||||||
export const Search = createIcon(Icons.mdiMagnify);
|
export const Search = createIcon(Icons.mdiMagnify);
|
||||||
export const Menu = createIcon(Icons.mdiMenu);
|
export const Menu = createIcon(Icons.mdiMenu);
|
||||||
export const Login = createIcon(Icons.mdiLoginVariant);
|
export const Login = createIcon(Icons.mdiLoginVariant);
|
||||||
|
export const Signup = createIcon(Icons.mdiAccountPlusOutline);
|
||||||
export const Logout = createIcon(Icons.mdiLogoutVariant);
|
export const Logout = createIcon(Icons.mdiLogoutVariant);
|
||||||
export const FocusMode = createIcon(Icons.mdiFullscreen);
|
export const FocusMode = createIcon(Icons.mdiFullscreen);
|
||||||
export const NormalMode = createIcon(Icons.mdiFullscreenExit);
|
export const NormalMode = createIcon(Icons.mdiFullscreenExit);
|
||||||
@@ -62,7 +63,7 @@ export const Home = createIcon(Icons.mdiHomeOutline);
|
|||||||
export const Restore = createIcon(Icons.mdiRecycle);
|
export const Restore = createIcon(Icons.mdiRecycle);
|
||||||
export const Sync = createIcon(Icons.mdiSync);
|
export const Sync = createIcon(Icons.mdiSync);
|
||||||
export const Loading = createIcon(Icons.mdiLoading, true);
|
export const Loading = createIcon(Icons.mdiLoading, true);
|
||||||
export const Export = createIcon(Icons.mdiExport);
|
export const Export = createIcon(Icons.mdiExportVariant);
|
||||||
export const AddToNotebook = createIcon(Icons.mdiBookPlusMultipleOutline);
|
export const AddToNotebook = createIcon(Icons.mdiBookPlusMultipleOutline);
|
||||||
|
|
||||||
/** Properties Icons */
|
/** Properties Icons */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Flex, Box, Text } from "rebass";
|
|||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import TimeAgo from "timeago-react";
|
import TimeAgo from "timeago-react";
|
||||||
import ListItem from "../list-item";
|
import ListItem from "../list-item";
|
||||||
import { confirm } from "../dialogs/confirm";
|
import { confirm, showDeleteConfirmation } from "../dialogs/confirm";
|
||||||
import { showMoveNoteDialog } from "../dialogs/movenotedialog";
|
import { showMoveNoteDialog } from "../dialogs/movenotedialog";
|
||||||
import { store, useStore } from "../../stores/note-store";
|
import { store, useStore } from "../../stores/note-store";
|
||||||
import { store as editorStore } from "../../stores/editor-store";
|
import { store as editorStore } from "../../stores/editor-store";
|
||||||
@@ -65,17 +65,31 @@ function menuItems(note, context) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
visible: context?.type === "topic",
|
visible: context?.type === "topic",
|
||||||
title: "Remove",
|
title: "Remove from topic",
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
confirm(
|
confirm(Icon.Topic, {
|
||||||
Icon.Topic,
|
title: "Remove Note from Topic",
|
||||||
"Remove from Topic",
|
subtitle: "Are you sure you want to remove the note from this topic?",
|
||||||
"Are you sure you want to remove this note?"
|
yesText: "Remove note",
|
||||||
).then(async (res) => {
|
noText: "Cancel",
|
||||||
|
message: (
|
||||||
|
<Text as="span">
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
This action does not delete the note.
|
||||||
|
</Text>{" "}
|
||||||
|
The note will only be removed from this notebook. You will still
|
||||||
|
be able to{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
access it from Home and other places.
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
}).then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
|
console.log(context);
|
||||||
await db.notebooks
|
await db.notebooks
|
||||||
.notebook(context.notebook.id)
|
.notebook(context.value.id)
|
||||||
.topics.topic(context.value)
|
.topics.topic(context.value.topic)
|
||||||
.delete(note.id);
|
.delete(note.id);
|
||||||
store.setContext(context);
|
store.setContext(context);
|
||||||
}
|
}
|
||||||
@@ -95,11 +109,7 @@ function menuItems(note, context) {
|
|||||||
});
|
});
|
||||||
if (!res) return;
|
if (!res) return;
|
||||||
}
|
}
|
||||||
confirm(
|
showDeleteConfirmation("note").then(async (res) => {
|
||||||
Icon.Trash,
|
|
||||||
"Delete",
|
|
||||||
"Are you sure you want to delete this note?"
|
|
||||||
).then(async (res) => {
|
|
||||||
if (res) {
|
if (res) {
|
||||||
await store.delete(note.id).then(() => showItemDeletedToast(note));
|
await store.delete(note.id).then(() => showItemDeletedToast(note));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import ListItem from "../list-item";
|
|||||||
import { store } from "../../stores/notebook-store";
|
import { store } from "../../stores/notebook-store";
|
||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import { showEditNoteDialog } from "../dialogs/addnotebookdialog";
|
import { showEditNoteDialog } from "../dialogs/addnotebookdialog";
|
||||||
import { confirm } from "../dialogs/confirm";
|
import { confirm, showDeleteConfirmation } from "../dialogs/confirm";
|
||||||
import { showItemDeletedToast, showUnpinnedToast } from "../../common/toasts";
|
import { showItemDeletedToast, showUnpinnedToast } from "../../common/toasts";
|
||||||
const pin = async (notebook, index) => {
|
const pin = async (notebook, index) => {
|
||||||
await store.pin(notebook, index);
|
await store.pin(notebook, index);
|
||||||
@@ -24,11 +24,7 @@ function menuItems(notebook, index) {
|
|||||||
title: "Delete",
|
title: "Delete",
|
||||||
color: "red",
|
color: "red",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
confirm(
|
showDeleteConfirmation("notebook").then(async (res) => {
|
||||||
Icon.Trash,
|
|
||||||
"Delete Notebook",
|
|
||||||
"Are you sure you want to delete this notebook?"
|
|
||||||
).then(async (res) => {
|
|
||||||
if (res) {
|
if (res) {
|
||||||
await store
|
await store
|
||||||
.delete(notebook.id, index)
|
.delete(notebook.id, index)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { confirm } from "../dialogs/confirm";
|
|||||||
import * as Icon from "../icons";
|
import * as Icon from "../icons";
|
||||||
import { db } from "../../common";
|
import { db } from "../../common";
|
||||||
import { store } from "../../stores/notebook-store";
|
import { store } from "../../stores/notebook-store";
|
||||||
|
import { Text } from "rebass";
|
||||||
|
|
||||||
const menuItems = (item) => [
|
const menuItems = (item) => [
|
||||||
{
|
{
|
||||||
@@ -19,11 +20,24 @@ const menuItems = (item) => [
|
|||||||
visible: item.title !== "General",
|
visible: item.title !== "General",
|
||||||
color: "red",
|
color: "red",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
confirm(
|
confirm(Icon.Trash, {
|
||||||
Icon.Trash,
|
title: "Delete topic",
|
||||||
"Delete Topic",
|
subtitle: "Are you sure you want to delete this topic?",
|
||||||
"Are you sure you want to delete this topic?"
|
yesText: "Delete topic",
|
||||||
).then(async (res) => {
|
noText: "Cancel",
|
||||||
|
message: (
|
||||||
|
<>
|
||||||
|
This action is{" "}
|
||||||
|
<Text as="span" color="error">
|
||||||
|
IRREVERSIBLE
|
||||||
|
</Text>
|
||||||
|
. Deleting this topic{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
will not delete the notes contained in it.
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
}).then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
await db.notebooks.notebook(item.notebookId).topics.delete(item.id);
|
await db.notebooks.notebook(item.notebookId).topics.delete(item.id);
|
||||||
store.setSelectedNotebookTopics(item.notebookId);
|
store.setSelectedNotebookTopics(item.notebookId);
|
||||||
|
|||||||
@@ -25,11 +25,24 @@ function menuItems(item, index) {
|
|||||||
title: "Delete",
|
title: "Delete",
|
||||||
color: "red",
|
color: "red",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
confirm(
|
confirm(Icon.Trash, {
|
||||||
Icon.Trash,
|
title: `Permanently Delete ${toTitleCase(item.itemType)}`,
|
||||||
"Delete",
|
subtitle: `Are you sure you want to permanently delete this ${item.itemType}?`,
|
||||||
`Are you sure you want to permanently delete this item?`
|
yesText: `Delete ${item.itemType}`,
|
||||||
).then(async (res) => {
|
noText: "Cancel",
|
||||||
|
message: (
|
||||||
|
<>
|
||||||
|
This action is{" "}
|
||||||
|
<Text as="span" color="error">
|
||||||
|
IRREVERSIBLE
|
||||||
|
</Text>
|
||||||
|
. You will{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
not be able to recover this {item.itemType}.
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
}).then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
await store.delete(item.id, index);
|
await store.delete(item.id, index);
|
||||||
showPermanentDeleteToast(item, index);
|
showPermanentDeleteToast(item, index);
|
||||||
@@ -54,7 +67,7 @@ function TrashItem({ item, index }) {
|
|||||||
<Text as="span" mx={1}>
|
<Text as="span" mx={1}>
|
||||||
•
|
•
|
||||||
</Text>
|
</Text>
|
||||||
<Text color="primary">{toTitleCase(item.type)}</Text>
|
<Text color="primary">{toTitleCase(item.itemType)}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
menuData={item}
|
menuData={item}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class FontSizeFactory {
|
|||||||
subtitle: 16 * scaleFactor,
|
subtitle: 16 * scaleFactor,
|
||||||
body: 16 * scaleFactor,
|
body: 16 * scaleFactor,
|
||||||
menu: 14 * scaleFactor,
|
menu: 14 * scaleFactor,
|
||||||
subBody: 11 * scaleFactor,
|
subBody: 12 * scaleFactor,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const routes = {
|
|||||||
<Notes
|
<Notes
|
||||||
context={{
|
context={{
|
||||||
type: "topic",
|
type: "topic",
|
||||||
value: { id: notebook, topic: topicItem.title },
|
value: { id: notebook, topic: topic },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ function Topics(props) {
|
|||||||
context={{ notebookId }}
|
context={{ notebookId }}
|
||||||
placeholder={Flex}
|
placeholder={Flex}
|
||||||
button={{
|
button={{
|
||||||
content: "Add more topics",
|
content: "Create a new topic",
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
await showTopicDialog(notebookId);
|
await showTopicDialog(notebookId);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { confirm } from "../components/dialogs/confirm";
|
|||||||
import { useStore, store } from "../stores/trash-store";
|
import { useStore, store } from "../stores/trash-store";
|
||||||
import TrashPlaceholder from "../components/placeholders/trash-placeholder";
|
import TrashPlaceholder from "../components/placeholders/trash-placeholder";
|
||||||
import { showToast } from "../utils/toast";
|
import { showToast } from "../utils/toast";
|
||||||
|
import { Text } from "rebass";
|
||||||
|
|
||||||
function Trash() {
|
function Trash() {
|
||||||
useEffect(() => store.refresh(), []);
|
useEffect(() => store.refresh(), []);
|
||||||
@@ -19,11 +20,24 @@ function Trash() {
|
|||||||
content: "Clear Trash",
|
content: "Clear Trash",
|
||||||
icon: Icon.Trash,
|
icon: Icon.Trash,
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
confirm(
|
confirm(Icon.Trash, {
|
||||||
Icon.Trash,
|
title: "Clear Trash",
|
||||||
"Clear",
|
subtitle: "Are you sure you want to clear all the trash?",
|
||||||
`This action is irreversible. Are you sure you want to proceed?`
|
yesText: "Clear trash",
|
||||||
).then(async (res) => {
|
noText: "Cancel",
|
||||||
|
message: (
|
||||||
|
<>
|
||||||
|
This action is{" "}
|
||||||
|
<Text as="span" color="error">
|
||||||
|
IRREVERSIBLE
|
||||||
|
</Text>
|
||||||
|
. You will{" "}
|
||||||
|
<Text as="span" color="primary">
|
||||||
|
not be able to recover any of these items.
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
}).then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
try {
|
try {
|
||||||
await clearTrash();
|
await clearTrash();
|
||||||
|
|||||||
Reference in New Issue
Block a user