Skip to content
This repository was archived by the owner on Mar 24, 2020. It is now read-only.

Commit 4a7053b

Browse files
authored
Merge pull request #20 from 0xGG/feat/wiki
Feat/wiki
2 parents f3518e9 + 4e987a9 commit 4a7053b

File tree

8 files changed

+290
-52
lines changed

8 files changed

+290
-52
lines changed

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
"emoji-mart": "^3.0.0",
3434
"ethers": "^4.0.46",
3535
"graphql": "^14.6.0",
36-
"gray-matter": "^4.0.2",
3736
"i18next": "^19.3.3",
3837
"identicon.js": "^2.3.3",
3938
"is_js": "^0.9.0",

src/components/Editor.tsx

+34-8
Original file line numberDiff line numberDiff line change
@@ -659,20 +659,14 @@ export default function Editor(props: Props) {
659659

660660
useEffect(() => {
661661
if (!editor || !note) return;
662-
const updateEditorMarkdown = () => {
663-
const readOnly = editor.getOption("readOnly");
664-
editor.setOption("readOnly", true);
665-
editor.setValue(isDecrypted ? note.markdown : "🔐 encrypted");
666-
editor.setOption("readOnly", readOnly);
667-
};
668662
if (editorMode === EditorMode.VickyMD) {
669663
VickyMD.switchToHyperMD(editor);
670664
editor.getWrapperElement().style.display = "block";
671-
updateEditorMarkdown();
665+
editor.refresh();
672666
} else if (editorMode === EditorMode.SourceCode) {
673667
VickyMD.switchToNormal(editor);
674668
editor.getWrapperElement().style.display = "block";
675-
updateEditorMarkdown();
669+
editor.refresh();
676670
} else {
677671
editor.getWrapperElement().style.display = "none";
678672
}
@@ -951,6 +945,38 @@ export default function Editor(props: Props) {
951945
}
952946
}, [needsToPrint, editorMode, note, editor, previewElement]);
953947

948+
// Wiki TOC Render
949+
useEffect(() => {
950+
if (
951+
note &&
952+
editor &&
953+
note.filePath === "SUMMARY.md" &&
954+
crossnoteContainer.wikiTOCElement
955+
) {
956+
const handleLinksClickEvent = (preview: HTMLElement) => {
957+
// Handle link click event
958+
const links = preview.getElementsByTagName("A");
959+
for (let i = 0; i < links.length; i++) {
960+
const link = links[i] as HTMLAnchorElement;
961+
link.onclick = event => {
962+
event.preventDefault();
963+
openURL(link.getAttribute("href"));
964+
};
965+
}
966+
};
967+
const onChangesHandler = () => {
968+
renderPreview(crossnoteContainer.wikiTOCElement, editor.getValue());
969+
handleLinksClickEvent(crossnoteContainer.wikiTOCElement);
970+
};
971+
editor.on("changes", onChangesHandler);
972+
renderPreview(crossnoteContainer.wikiTOCElement, editor.getValue());
973+
handleLinksClickEvent(crossnoteContainer.wikiTOCElement);
974+
return () => {
975+
editor.off("changes", onChangesHandler);
976+
};
977+
}
978+
}, [note, editor, crossnoteContainer.wikiTOCElement]);
979+
954980
if (!note) {
955981
return (
956982
<Box className={clsx(classes.editorPanel, "editor-panel")}>

src/components/NotebookTreeView.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,37 @@ export default function NotebookTreeView(props: Props) {
338338
>
339339
{constructDirectoryTreeItems(crossnoteContainer.notebookDirectories)}
340340
</TreeItem>
341+
{crossnoteContainer.hasSummaryMD ? (
342+
<TreeItem
343+
nodeId={"wiki"}
344+
classes={{
345+
root: classes.treeItemRoot,
346+
content: classes.treeItemContent,
347+
expanded: classes.treeItemExpanded,
348+
group: classes.treeItemGroup,
349+
label: classes.treeItemLabel
350+
}}
351+
label={
352+
<Box
353+
onClick={() => {
354+
crossnoteContainer.setSelectedSection({
355+
type: SelectedSectionType.Wiki
356+
});
357+
}}
358+
className={clsx(classes.treeItemLabelRoot)}
359+
>
360+
<span role="img" aria-label="wiki">
361+
📖
362+
</span>
363+
<Typography className={clsx(classes.treeItemLabelText)}>
364+
{"wiki"}
365+
</Typography>
366+
</Box>
367+
}
368+
></TreeItem>
369+
) : (
370+
<TreeItem nodeId={"wiki"}></TreeItem>
371+
)}
341372
<TreeItem
342373
nodeId={"tagged-notes"}
343374
classes={{

src/components/WikiPanel.tsx

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import React, { useState, useEffect } from "react";
2+
import {
3+
fade,
4+
createStyles,
5+
makeStyles,
6+
Theme
7+
} from "@material-ui/core/styles";
8+
import clsx from "clsx";
9+
import {
10+
CrossnoteContainer,
11+
SelectedSectionType,
12+
OrderBy,
13+
OrderDirection
14+
} from "../containers/crossnote";
15+
import {
16+
Box,
17+
InputBase,
18+
Card,
19+
IconButton,
20+
Typography,
21+
Hidden,
22+
CircularProgress,
23+
Popover,
24+
List,
25+
ListItem,
26+
ListItemText,
27+
ListItemIcon,
28+
Divider
29+
} from "@material-ui/core";
30+
import {
31+
Magnify,
32+
FileEditOutline,
33+
Settings,
34+
Menu as MenuIcon,
35+
SortVariant,
36+
SortDescending,
37+
SortAscending
38+
} from "mdi-material-ui";
39+
import { useTranslation } from "react-i18next";
40+
41+
const previewZIndex = 99;
42+
const useStyles = makeStyles((theme: Theme) =>
43+
createStyles({
44+
wikiPanel: {
45+
position: "relative",
46+
display: "flex",
47+
flexDirection: "column",
48+
height: "100%"
49+
},
50+
topPanel: {
51+
padding: theme.spacing(1)
52+
},
53+
row: {
54+
display: "flex",
55+
alignItems: "center"
56+
},
57+
sectionName: {
58+
marginLeft: theme.spacing(1)
59+
},
60+
toc: {
61+
position: "relative",
62+
flex: "1",
63+
overflowY: "auto",
64+
paddingBottom: theme.spacing(12)
65+
},
66+
preview: {
67+
position: "relative",
68+
left: "0",
69+
top: "0",
70+
margin: "4px",
71+
width: "calc(100% - 8px)",
72+
height: "100%",
73+
border: "none",
74+
overflow: "auto !important",
75+
padding: theme.spacing(2),
76+
zIndex: previewZIndex,
77+
[theme.breakpoints.down("sm")]: {
78+
padding: theme.spacing(1)
79+
}
80+
// gridArea: "2 / 2 / 3 / 3"
81+
}
82+
})
83+
);
84+
85+
interface Props {
86+
toggleDrawer: () => void;
87+
}
88+
89+
export default function WikiPanel(props: Props) {
90+
const classes = useStyles(props);
91+
const { t } = useTranslation();
92+
const crossnoteContainer = CrossnoteContainer.useContainer();
93+
94+
useEffect(() => {
95+
return () => {
96+
crossnoteContainer.setWikiTOCElement(null);
97+
};
98+
}, []);
99+
100+
return (
101+
<Box className={clsx(classes.wikiPanel)}>
102+
<Card className={clsx(classes.topPanel)}>
103+
<Box className={clsx(classes.row)}>
104+
<Hidden smUp implementation="css">
105+
<IconButton onClick={props.toggleDrawer}>
106+
<MenuIcon></MenuIcon>
107+
</IconButton>
108+
</Hidden>
109+
<Box className={clsx(classes.row)}>
110+
<span role="img" aria-label="wiki">
111+
📖
112+
</span>
113+
<Typography className={clsx(classes.sectionName)}>
114+
{"wiki"}
115+
</Typography>
116+
</Box>
117+
{/*<IconButton
118+
onClick={() => {
119+
crossnoteContainer.createNewNote();
120+
}}
121+
>
122+
<FileEditOutline></FileEditOutline>
123+
</IconButton>*/}
124+
</Box>
125+
</Card>
126+
<div
127+
className={clsx(classes.toc, classes.preview, "preview")}
128+
ref={(element: HTMLElement) => {
129+
crossnoteContainer.setWikiTOCElement(element);
130+
}}
131+
></div>
132+
</Box>
133+
);
134+
}

src/containers/crossnote.ts

+38-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ export enum SelectedSectionType {
2525
Directory = "Directory",
2626
Tag = "Tag",
2727
Conflicted = "Conflicted",
28-
Encrypted = "Encrypted"
28+
Encrypted = "Encrypted",
29+
Wiki = "Wiki"
2930
}
3031

3132
export interface SelectedSection {
@@ -81,7 +82,9 @@ function useCrossnoteContainer(initialState: InitialState) {
8182
const [needsToRefreshNotes, setNeedsToRefreshNotes] = useState<boolean>(
8283
false
8384
);
85+
const [wikiTOCElement, setWikiTOCElement] = useState<HTMLElement>(null);
8486
const [isLoadingNotebook, setIsLoadingNotebook] = useState<boolean>(false);
87+
const [hasSummaryMD, setHasSummaryMD] = useState<boolean>(false);
8588
const [orderBy, setOrderBy] = useState<OrderBy>(OrderBy.ModifiedAt);
8689
const [orderDirection, setOrderDirection] = useState<OrderDirection>(
8790
OrderDirection.DESC
@@ -117,12 +120,12 @@ function useCrossnoteContainer(initialState: InitialState) {
117120
);
118121

119122
const deleteNote = useCallback(
120-
(note: Note) => {
121-
crossnote.deleteNote(selectedNotebook, note.filePath);
123+
async (note: Note) => {
124+
await crossnote.deleteNote(selectedNotebook, note.filePath);
122125
setNotebookNotes(notes => {
123126
const newNotes = notes.filter(n => n.filePath !== note.filePath);
124127
if (newNotes.length !== notes.length) {
125-
setSelectedNote(newNotes[0]);
128+
setSelectedNote(null);
126129
}
127130

128131
crossnote
@@ -131,6 +134,10 @@ function useCrossnoteContainer(initialState: InitialState) {
131134
setNotebookDirectories(directories);
132135
});
133136

137+
crossnote
138+
.hasSummaryMD(selectedNotebook)
139+
.then(exists => setHasSummaryMD(exists));
140+
134141
setNotebookTagNode(crossnote.getNotebookTagNodeFromNotes(newNotes));
135142
return newNotes;
136143
});
@@ -161,6 +168,7 @@ function useCrossnoteContainer(initialState: InitialState) {
161168
setNotebookDirectories(
162169
await crossnote.getNotebookDirectoriesFromNotes(newNotes)
163170
);
171+
setHasSummaryMD(await crossnote.hasSummaryMD(selectedNotebook));
164172
setNotebookTagNode(crossnote.getNotebookTagNodeFromNotes(newNotes));
165173
} catch (error) {
166174
new Noty({
@@ -316,6 +324,7 @@ function useCrossnoteContainer(initialState: InitialState) {
316324
}
317325
setIsPullingNotebook(true);
318326
try {
327+
// NOTE: Code here might have bug
319328
await crossnote.pullNotebook(args);
320329
setIsPullingNotebook(false);
321330
const notes = await crossnote.listNotes({
@@ -327,6 +336,7 @@ function useCrossnoteContainer(initialState: InitialState) {
327336
setNotebookDirectories(
328337
await crossnote.getNotebookDirectoriesFromNotes(notes)
329338
);
339+
setHasSummaryMD(await crossnote.hasSummaryMD(args.notebook));
330340
setNotebookTagNode(crossnote.getNotebookTagNodeFromNotes(notes));
331341

332342
const newNote = notes.find(n => n.filePath === selectedNote.filePath);
@@ -378,6 +388,9 @@ function useCrossnoteContainer(initialState: InitialState) {
378388
.then(directories => {
379389
setNotebookDirectories(directories);
380390
});
391+
crossnote
392+
.hasSummaryMD(selectedNotebook)
393+
.then(exists => setHasSummaryMD(exists));
381394
setNotebookTagNode(crossnote.getNotebookTagNodeFromNotes(newNotes));
382395
return newNotes;
383396
});
@@ -388,7 +401,7 @@ function useCrossnoteContainer(initialState: InitialState) {
388401
});
389402
}
390403
},
391-
[crossnote]
404+
[crossnote, selectedNotebook]
392405
);
393406

394407
const updateNotebookTagNode = useCallback(() => {
@@ -463,6 +476,7 @@ function useCrossnoteContainer(initialState: InitialState) {
463476
path: ".",
464477
children: []
465478
});
479+
setHasSummaryMD(false);
466480
setNotebookTagNode({
467481
name: ".",
468482
path: ".",
@@ -478,6 +492,7 @@ function useCrossnoteContainer(initialState: InitialState) {
478492
setNotebookDirectories(
479493
await crossnote.getNotebookDirectoriesFromNotes(notes)
480494
);
495+
setHasSummaryMD(await crossnote.hasSummaryMD(selectedNotebook));
481496
setNotebookTagNode(crossnote.getNotebookTagNodeFromNotes(notes));
482497
setSelectedNote(null);
483498
setIsLoadingNotebook(false);
@@ -532,6 +547,8 @@ function useCrossnoteContainer(initialState: InitialState) {
532547
notes = notebookNotes.filter(note => {
533548
return note.config.encryption;
534549
});
550+
} else if (selectedSection.type === SelectedSectionType.Wiki) {
551+
// Do nothing here
535552
} else {
536553
// SelectedSectionType.Directory
537554
if (includeSubdirectories) {
@@ -572,14 +589,22 @@ function useCrossnoteContainer(initialState: InitialState) {
572589
} else if (orderBy === OrderBy.Title) {
573590
if (orderDirection === OrderDirection.DESC) {
574591
notes.sort((a, b) =>
575-
getHeaderFromMarkdown(b.markdown).localeCompare(
576-
getHeaderFromMarkdown(a.markdown)
592+
(
593+
(b.config.encryption && b.config.encryption.title) ||
594+
getHeaderFromMarkdown(b.markdown)
595+
).localeCompare(
596+
(a.config.encryption && a.config.encryption.title) ||
597+
getHeaderFromMarkdown(a.markdown)
577598
)
578599
);
579600
} else {
580601
notes.sort((a, b) =>
581-
getHeaderFromMarkdown(a.markdown).localeCompare(
582-
getHeaderFromMarkdown(b.markdown)
602+
(
603+
(a.config.encryption && a.config.encryption.title) ||
604+
getHeaderFromMarkdown(a.markdown)
605+
).localeCompare(
606+
(b.config.encryption && b.config.encryption.title) ||
607+
getHeaderFromMarkdown(b.markdown)
583608
)
584609
);
585610
}
@@ -652,7 +677,10 @@ function useCrossnoteContainer(initialState: InitialState) {
652677
orderBy,
653678
setOrderBy,
654679
orderDirection,
655-
setOrderDirection
680+
setOrderDirection,
681+
hasSummaryMD,
682+
wikiTOCElement,
683+
setWikiTOCElement
656684
};
657685
}
658686

0 commit comments

Comments
 (0)