web: add clear instructions on how to import from other apps

This commit is contained in:
Abdullah Atta
2024-09-09 13:14:17 +05:00
parent 983220b2f2
commit 2f7b8d3377
3 changed files with 193 additions and 89 deletions

View File

@@ -29,12 +29,22 @@ export type AccordionProps = {
testId?: string;
buttonSx?: FlexProps["sx"];
titleSx?: FlexProps["sx"];
containerSx?: FlexProps["sx"];
};
export default function Accordion(
props: PropsWithChildren<AccordionProps> & FlexProps
) {
const { isClosed, title, color, children, testId, sx, ...restProps } = props;
const {
isClosed,
title,
color,
children,
testId,
sx,
containerSx,
...restProps
} = props;
const [isContentHidden, setIsContentHidden] = useState(false);
useEffect(() => {
@@ -69,8 +79,9 @@ export default function Accordion(
</Flex>
<Flex
sx={{
display: isContentHidden ? "none" : "flex",
flexDirection: "column"
flexDirection: "column",
...containerSx,
display: isContentHidden ? "none" : "flex"
}}
>
{children}

View File

@@ -20,11 +20,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useStore as useAppStore } from "../../../stores/app-store";
import { useCallback, useRef, useState } from "react";
import { useDropzone } from "react-dropzone";
import { Button, Flex, Input, Link, Text } from "@theme-ui/components";
import { pluralize } from "@notesnook/common";
import { Box, Button, Flex, Input, Link, Text } from "@theme-ui/components";
import { db } from "../../../common/db";
import { importFiles } from "../../../utils/importer";
import { CheckCircleOutline } from "../../../components/icons";
import Accordion from "../../../components/accordion";
type Provider = { title: string; link: string };
const POPULAR_PROVIDERS: Provider[] = [
{
title: "Evernote",
link: "https://help.notesnook.com/importing-notes/import-notes-from-evernote"
},
{
title: "Simplenote",
link: "https://help.notesnook.com/importing-notes/import-notes-from-simplenote"
},
{
title: "Google Keep",
link: "https://help.notesnook.com/importing-notes/import-notes-from-google-keep"
},
{
title: "Obsidian",
link: "https://help.notesnook.com/importing-notes/import-notes-from-obsidian"
},
{
title: "Joplin",
link: "https://help.notesnook.com/importing-notes/import-notes-from-joplin"
},
{
title: "Markdown files",
link: "https://help.notesnook.com/importing-notes/import-notes-from-markdown-files"
},
{
title: "other apps",
link: "https://help.notesnook.com/importing-notes/"
}
];
export function Importer() {
const [isDone, setIsDone] = useState(false);
@@ -114,75 +146,81 @@ export function Importer() {
</>
) : (
<>
<Flex sx={{ alignItems: "center", justifyContent: "space-between" }}>
<Flex sx={{ flexDirection: "column" }}>
<Text variant="title">
{files.length
? `${pluralize(files.length, "file")} ready for import`
: "Select files to import"}
<Accordion
isClosed={false}
title="How to import your notes from other apps?"
containerSx={{
px: 2,
pb: 2,
border: "1px solid var(--border)",
borderTopWidth: 0,
borderRadius: "default",
borderTopLeftRadius: 0,
borderTopRightRadius: 0
}}
>
<Text variant="subtitle" sx={{ mt: 2 }}>
Quick start guide:
</Text>
<Box as="ol" sx={{ my: 1 }}>
<Text as="li" variant="body">
Go to{" "}
<Link href="https://importer.notesnook.com/" target="_blank">
https://importer.notesnook.com/
</Link>
</Text>
<Text
variant={"body"}
sx={{ color: "var(--paragraph-secondary)" }}
>
Please refer to the{" "}
<Link
href="https://help.notesnook.com/importing-notes/import-notes-from-evernote"
target="_blank"
rel="noopener noreferrer"
sx={{ color: "accent" }}
>
import guide
</Link>{" "}
for help regarding how to use the Notesnook Importer.
<Text as="li" variant="body">
Select the app you want to import from.
</Text>
</Flex>
<Button
variant="accent"
onClick={async () => {
setIsDone(false);
setIsImporting(true);
<Text as="li" variant="body">
Drag drop or select the files you exported from the other app.
</Text>
<Text as="li" variant="body">
Start the importer and wait for it to complete processing.
</Text>
<Text as="li" variant="body">
Download the .zip file from the Importer.
</Text>
<Text as="li" variant="body">
Drop the .zip file below to complete your import.
</Text>
</Box>
await db.syncer?.acquireLock(async () => {
try {
for await (const message of importFiles(files)) {
switch (message.type) {
case "error":
setErrors((errors) => [...errors, message.error]);
break;
case "progress": {
const { count } = message;
if (notesCounter.current)
notesCounter.current.innerText = `${count}`;
break;
}
}
}
} catch (e) {
console.error(e);
if (e instanceof Error) {
setErrors((errors) => [...errors, e as Error]);
}
}
});
await useAppStore.getState().refresh();
setIsDone(true);
setIsImporting(false);
<Text variant={"body"} sx={{ fontWeight: "bold" }}>
For detailed steps with screenshots, refer to the help article for
each app:
</Text>
<Box
sx={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
gap: 1,
mt: 1
}}
disabled={!files.length}
>
Start import
</Button>
</Flex>
{POPULAR_PROVIDERS.map((provider) => (
<Button
key={provider.link}
variant="icon"
sx={{
borderRadius: "default",
border: "1px solid var(--border)",
textAlign: "left"
}}
onClick={() => window.open(provider.link, "_blank")}
>
Import from {provider.title}
</Button>
))}
</Box>
</Accordion>
<Flex
{...getRootProps()}
data-test-id="import-dialog-select-files"
sx={{
justifyContent: "center",
alignItems: "center",
height: 200,
minHeight: 200,
flexShrink: 0,
width: "full",
border: "2px dashed var(--border)",
@@ -199,31 +237,75 @@ export function Importer() {
<br />
<Text variant="subBody">Only .zip files are supported.</Text>
</Text>
<Box sx={{ display: "flex", flexWrap: "wrap", mt: 2 }}>
{files.map((file, i) => (
<Text
key={file.name}
p={1}
sx={{
":hover": { bg: "hover" },
cursor: "pointer",
borderRadius: "default"
}}
onClick={() => {
setFiles((files) => {
const cloned = files.slice();
cloned.splice(i, 1);
return cloned;
});
}}
variant="body"
title="Click to remove"
>
{file.name}
</Text>
))}
</Box>
</Flex>
<Flex my={1} sx={{ flexDirection: "column" }}>
{files.map((file, i) => (
<Text
key={file.name}
p={1}
sx={{
":hover": { bg: "hover" },
cursor: "pointer",
borderRadius: "default"
}}
onClick={() => {
setFiles((files) => {
const cloned = files.slice();
cloned.splice(i, 1);
return cloned;
});
}}
variant="body"
title="Click to remove"
>
{file.name}
</Text>
))}
</Flex>
{/* <Flex my={1} sx={{ flexDirection: "column" }}>
</Flex> */}
<Button
variant="accent"
sx={{ alignSelf: "end", mt: 1 }}
onClick={async () => {
setIsDone(false);
setIsImporting(true);
await db.syncer?.acquireLock(async () => {
try {
for await (const message of importFiles(files)) {
switch (message.type) {
case "error":
setErrors((errors) => [...errors, message.error]);
break;
case "progress": {
const { count } = message;
if (notesCounter.current)
notesCounter.current.innerText = `${count}`;
break;
}
}
}
} catch (e) {
console.error(e);
if (e instanceof Error) {
setErrors((errors) => [...errors, e as Error]);
}
}
});
await useAppStore.getState().refresh();
setIsDone(true);
setIsImporting(false);
}}
disabled={!files.length}
>
{files.length > 0
? "Start import"
: "Select files to start importing"}
</Button>
</>
)}
</Flex>

View File

@@ -24,7 +24,18 @@ export const ImporterSettings: SettingsGroup[] = [
{
key: "importer",
section: "importer",
header: Importer,
settings: []
header: "Notesnook Importer",
settings: [
{
key: "import-notes",
title: "",
components: [
{
type: "custom",
component: Importer
}
]
}
]
}
];