mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-01 03:29:21 +02:00
Compare commits
29 Commits
3.2.10-and
...
mobile-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a63a45d00 | ||
|
|
4e44661e1b | ||
|
|
81fd1c097e | ||
|
|
aaf82f359b | ||
|
|
a1d8b34fb4 | ||
|
|
874352e753 | ||
|
|
49d1ab4be5 | ||
|
|
65a80dbd46 | ||
|
|
e55456f492 | ||
|
|
3f9fce0d34 | ||
|
|
2ae094cf1f | ||
|
|
bc224f1674 | ||
|
|
8bb1582cca | ||
|
|
d02125a93c | ||
|
|
d91ce4e936 | ||
|
|
deb902549b | ||
|
|
e41ed07805 | ||
|
|
f6e8dc0a88 | ||
|
|
044dd5ce59 | ||
|
|
b24830666c | ||
|
|
470802c3e2 | ||
|
|
7e0e1eac93 | ||
|
|
58cbf653b2 | ||
|
|
4b35f2ecd2 | ||
|
|
48d9a863ec | ||
|
|
1d616cf68f | ||
|
|
fb1eb234b6 | ||
|
|
7e70cd96b9 | ||
|
|
f9a89783ed |
@@ -24,7 +24,7 @@ Requirements:
|
||||
|
||||
Before you can do anything, you'll need to [install Node.js](https://nodejs.org/en/download/) v16 or later on your system.
|
||||
|
||||
Once you have completed the setup, the first step is to `clone` the monorepo:
|
||||
1. `clone` the monorepo:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/streetwriters/notesnook.git
|
||||
@@ -33,19 +33,28 @@ git clone https://github.com/streetwriters/notesnook.git
|
||||
cd notesnook
|
||||
```
|
||||
|
||||
Once you are inside the `./notesnook` directory, run the preparation step:
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
# this might take a while to complete
|
||||
npm install
|
||||
```
|
||||
|
||||
Now you can finally start the desktop app for development:
|
||||
3. Run the webapp for desktop environment:
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
4. In a separate terminal session, run the desktop app from the root of the project:
|
||||
|
||||
```bash
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
### Release mode
|
||||
|
||||
To run the app in release mode:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -137,6 +137,7 @@ export async function deleteFile(
|
||||
|
||||
export async function clearFileStorage() {
|
||||
try {
|
||||
await createCacheDir();
|
||||
const files = await RNFetchBlob.fs.ls(cacheDir);
|
||||
const oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
|
||||
|
||||
@@ -221,6 +222,7 @@ export async function deleteCacheFileByName(name: string) {
|
||||
}
|
||||
|
||||
export async function deleteDCacheFiles() {
|
||||
await createCacheDir();
|
||||
const files = await RNFetchBlob.fs.ls(cacheDir);
|
||||
for (const file of files) {
|
||||
if (file.includes("_dcache") || file.startsWith("NN_")) {
|
||||
|
||||
@@ -33,6 +33,9 @@ export function hideAuth() {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
if (initialAuthMode.current === AuthMode.welcomeSignup) {
|
||||
Navigation.replace("FluidPanelsView");
|
||||
setTimeout(() => {
|
||||
Navigation.resetRootState();
|
||||
}, 300);
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ const Auth = ({ navigation, route }) => {
|
||||
onPress={() => {
|
||||
if (initialAuthMode.current === 2) {
|
||||
Navigation.replace("FluidPanelsView");
|
||||
setTimeout(() => {
|
||||
Navigation.resetRootState();
|
||||
}, 300);
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
|
||||
@@ -310,6 +310,7 @@ const ExportNotesSheet = ({
|
||||
ToastManager.error(e as Error);
|
||||
});
|
||||
} else {
|
||||
await sleep(500);
|
||||
FileViewer.open(result?.filePath, {
|
||||
showOpenWithDialog: true,
|
||||
showAppsSuggestions: true
|
||||
@@ -338,6 +339,7 @@ const ExportNotesSheet = ({
|
||||
.getState()
|
||||
.setAppDidEnterBackgroundForAction(true);
|
||||
if (Platform.OS === "ios") {
|
||||
await sleep(500);
|
||||
Share.open({
|
||||
url: result?.fileDir + result.fileName
|
||||
}).catch(() => {
|
||||
|
||||
@@ -38,8 +38,8 @@ import { eCloseSheet, eOnNotebookUpdated } from "../../../utils/events";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import { Dialog } from "../../dialog";
|
||||
import { Properties } from "../../properties";
|
||||
import SheetProvider from "../../sheet-provider";
|
||||
import { NotebookItem } from "../../side-menu/notebook-item";
|
||||
import { useSideMenuNotebookTreeStore } from "../../side-menu/stores";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
@@ -151,7 +151,7 @@ export const Notebooks = (props: {
|
||||
height: 400
|
||||
}}
|
||||
>
|
||||
<SheetProvider context="local" />
|
||||
<Dialog context="local" />
|
||||
|
||||
<View
|
||||
style={{
|
||||
@@ -175,7 +175,7 @@ export const Notebooks = (props: {
|
||||
}}
|
||||
name="plus"
|
||||
onPress={() => {
|
||||
AddNotebookSheet.present(props.rootNotebook, undefined, "local");
|
||||
AddNotebookSheet.present(undefined, props.rootNotebook, "local");
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -66,7 +66,7 @@ export const SideMenuNotebooks = () => {
|
||||
if (lastQuery.current) {
|
||||
db.lookup
|
||||
.notebooks(lastQuery.current)
|
||||
.sorted()
|
||||
.sorted(db.settings.getGroupOptions("notebooks"))
|
||||
.then((filtered) => {
|
||||
setFilteredNotebooks(filtered);
|
||||
});
|
||||
|
||||
@@ -220,7 +220,7 @@ export const SideMenuTags = () => {
|
||||
if (lastQuery.current) {
|
||||
db.lookup
|
||||
.tags(lastQuery.current.trim())
|
||||
.sorted()
|
||||
.sorted(db.settings.getGroupOptions("tags"))
|
||||
.then(async (filtered) => {
|
||||
setFilteredTags(filtered);
|
||||
});
|
||||
|
||||
@@ -166,6 +166,20 @@ function closeDrawer() {
|
||||
fluidTabsRef.current?.closeDrawer();
|
||||
}
|
||||
|
||||
function resetRootState() {
|
||||
const state = rootNavigatorRef.getState();
|
||||
const focusedRouteKey = state.routes[state.index].key;
|
||||
const routes = state.routes.filter(
|
||||
(route) => route.name !== "Auth" && route.name !== "Welcome"
|
||||
);
|
||||
const newIndex = routes.findIndex((route) => route.key === focusedRouteKey);
|
||||
rootNavigatorRef.reset({
|
||||
...state,
|
||||
routes: routes,
|
||||
index: newIndex
|
||||
});
|
||||
}
|
||||
|
||||
const Navigation = {
|
||||
navigate,
|
||||
goBack,
|
||||
@@ -177,7 +191,8 @@ const Navigation = {
|
||||
queueRoutesForUpdate,
|
||||
routeNeedsUpdate,
|
||||
routeNames,
|
||||
routeUpdateFunctions
|
||||
routeUpdateFunctions,
|
||||
resetRootState
|
||||
};
|
||||
|
||||
export default Navigation;
|
||||
|
||||
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getFormattedReminderTime } from "@notesnook/common";
|
||||
import { isReminderActive, Reminder } from "@notesnook/core";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import notifee, {
|
||||
@@ -36,6 +37,7 @@ import dayjs, { Dayjs } from "dayjs";
|
||||
import { encodeNonAsciiHTML } from "entities";
|
||||
import { Platform } from "react-native";
|
||||
import { db, setupDatabase } from "../common/database";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
import { useTabStore } from "../screens/editor/tiptap/use-tab-store";
|
||||
import { editorState } from "../screens/editor/tiptap/utils";
|
||||
@@ -52,8 +54,6 @@ import { DDS } from "./device-detection";
|
||||
import { eSendEvent } from "./event-manager";
|
||||
import Navigation from "./navigation";
|
||||
import SettingsService from "./settings";
|
||||
import { getFormattedReminderTime } from "@notesnook/common";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
|
||||
let pinned: DisplayedNotification[] = [];
|
||||
|
||||
@@ -454,7 +454,7 @@ async function loadNote(id: string, jump: boolean) {
|
||||
const tab = useTabStore.getState().getTabForNote(id);
|
||||
if (useTabStore.getState().currentTab !== tab) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
note: note
|
||||
item: note
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ rootProject.name = 'Notesnook'
|
||||
include ':app'
|
||||
includeBuild('../../node_modules/@react-native/gradle-plugin')
|
||||
|
||||
include ":lazysodium"
|
||||
project(':lazysodium').projectDir = new File(rootProject.projectDir, '../../node_modules/@ammarahmed/react-native-sodium/android/lazysodium')
|
||||
include ":lazysodium-android"
|
||||
project(':lazysodium-android').projectDir = new File(rootProject.projectDir, '../../node_modules/@ammarahmed/react-native-sodium/android/lazysodium-android/app')
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"react-native-screenguard": "^1.0.0",
|
||||
"@formatjs/intl-locale": "4.0.0",
|
||||
"@formatjs/intl-pluralrules": "5.2.14",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.4",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.5",
|
||||
"@react-native-community/datetimepicker": "^8.2.0",
|
||||
"react-native-exit-app": "github:ammarahm-ed/react-native-exit-app",
|
||||
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
|
||||
|
||||
337
apps/mobile/package-lock.json
generated
337
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -56,4 +56,4 @@
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.77.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useState, Suspense, useEffect, useRef } from "react";
|
||||
import { Suspense, useEffect, useRef } from "react";
|
||||
import { Box, Flex } from "@theme-ui/components";
|
||||
import { ScopedThemeProvider } from "./components/theme-provider";
|
||||
import useMobile from "./hooks/use-mobile";
|
||||
@@ -224,7 +224,7 @@ function DesktopAppContents() {
|
||||
initialSize={380}
|
||||
style={{ flex: 1, display: "flex" }}
|
||||
snapSize={120}
|
||||
maxSize={500}
|
||||
maxSize={1000}
|
||||
className="list-pane"
|
||||
>
|
||||
<ScopedThemeProvider
|
||||
|
||||
@@ -75,7 +75,10 @@ const actions: Partial<
|
||||
isCommandMode: false
|
||||
}).catch(() => {});
|
||||
},
|
||||
openSettings: () => hashNavigate("/settings", { replace: true }),
|
||||
openSettings: (e) => {
|
||||
if (isInEditor(e)) return;
|
||||
hashNavigate("/settings", { replace: true });
|
||||
},
|
||||
openKeyboardShortcuts: () => KeyboardShortcutsDialog.show({})
|
||||
};
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@ function Reminders() {
|
||||
useNavigate("reminders", () => store.refresh());
|
||||
const reminders = useStore((state) => state.reminders);
|
||||
const refresh = useStore((state) => state.refresh);
|
||||
const filteredItems = useSearch("reminders", (query, sortOptions) =>
|
||||
db.lookup.reminders(query).sorted(sortOptions)
|
||||
const filteredItems = useSearch(
|
||||
"reminders",
|
||||
(query, sortOptions) => db.lookup.reminders(query).sorted(sortOptions),
|
||||
[reminders]
|
||||
);
|
||||
|
||||
if (!reminders) return <ListLoader />;
|
||||
|
||||
@@ -22,7 +22,7 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
|
||||
| --- | --- | --- | --- |
|
||||
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
|
||||
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
|
||||
| Command palette | Ctrl K | Ctrl K | ⌘ K |
|
||||
| Command palette | Ctrl ⇧ P | Ctrl ⇧ P | ⌘ ⇧ P |
|
||||
| Quick open | Ctrl P | Ctrl P | ⌘ P |
|
||||
| New tab | - | Ctrl T | ⌘ T |
|
||||
| Close active tab | - | Ctrl W | ⌘ W |
|
||||
@@ -60,8 +60,8 @@ The following keyboard shortcuts will help you navigate Notesnook faster.
|
||||
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
|
||||
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
|
||||
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
|
||||
| Insert internal link | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
|
||||
| Insert link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
|
||||
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
|
||||
| Insert link | Ctrl K | Ctrl K | ⌘ K |
|
||||
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
|
||||
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
|
||||
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
|
||||
|
||||
@@ -96,7 +96,7 @@ export const hotkeys = {
|
||||
type: "hotkeys"
|
||||
},
|
||||
openCommandPalette: {
|
||||
keys: normalizeKeys(["ctrl+k"]),
|
||||
keys: normalizeKeys(["ctrl+shift+p"]),
|
||||
description: "Command palette",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
@@ -294,13 +294,13 @@ export const tiptapKeys = {
|
||||
type: "tiptap"
|
||||
},
|
||||
insertInternalLink: {
|
||||
keys: "Mod-Shift-L",
|
||||
keys: "Mod-Shift-K",
|
||||
description: "Insert internal link",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertLink: {
|
||||
keys: "Mod-Shift-K",
|
||||
keys: "Mod-k",
|
||||
description: "Insert link",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
@@ -330,7 +330,7 @@ export const tiptapKeys = {
|
||||
type: "tiptap"
|
||||
},
|
||||
openSearch: {
|
||||
keys: "Mod-F",
|
||||
keys: "Mod-f",
|
||||
description: "Open search",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
|
||||
@@ -232,9 +232,10 @@ export const Link = Mark.create<LinkOptions>({
|
||||
}
|
||||
}),
|
||||
markPasteRule({
|
||||
find: (text) => {
|
||||
find: (text, ev) => {
|
||||
const foundLinks: PasteRuleMatch[] = [];
|
||||
|
||||
const html = ev?.clipboardData?.getData("text/html");
|
||||
if (html && html.includes("<a")) return [];
|
||||
if (text) {
|
||||
const links = find(text).filter((item) => item.isLink);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`paste text > with html link 1`] = `"<div><div contenteditable="true" translate="no" class="tiptap ProseMirror" tabindex="0"><p><a target="_blank" rel="noopener noreferrer nofollow" spellcheck="false" href="nn://note/68798972093c8c6ea22efca2">example.py</a></p></div></div>"`;
|
||||
|
||||
exports[`paste text > with markdown link 1`] = `"<div><div contenteditable="true" translate="no" class="tiptap ProseMirror" tabindex="0"><p><a target="_blank" rel="noopener noreferrer nofollow" spellcheck="false" href="example.com">test</a></p></div></div>"`;
|
||||
|
||||
exports[`paste text > with multiple markdown links 1`] = `"<div><div contenteditable="true" translate="no" class="tiptap ProseMirror" tabindex="0"><p><a target="_blank" rel="noopener noreferrer nofollow" spellcheck="false" href="example.com">test</a> some text <a target="_blank" rel="noopener noreferrer nofollow" spellcheck="false" href="example2.com">test2</a></p></div></div>"`;
|
||||
|
||||
@@ -114,4 +114,33 @@ describe("paste text", () => {
|
||||
|
||||
expect(editorElement.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("with html link", async () => {
|
||||
const editorElement = h("div");
|
||||
const { editor } = createEditor({
|
||||
element: editorElement,
|
||||
extensions: {
|
||||
link: Link
|
||||
}
|
||||
});
|
||||
|
||||
const clipboardEvent = new Event("paste", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true
|
||||
});
|
||||
|
||||
(clipboardEvent as unknown as any)["clipboardData"] = {
|
||||
getData: (type: string) =>
|
||||
type === "text/html"
|
||||
? `<meta charset='utf-8'><html><head></head><body><a href="nn://note/68798972093c8c6ea22efca2">example.py</a></body></html>`
|
||||
: ""
|
||||
};
|
||||
|
||||
editor.view.dom.dispatchEvent(clipboardEvent);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
expect(editorElement.outerHTML).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -196,6 +196,7 @@ export function OpenLink(props: ToolProps) {
|
||||
const link = node ? findMark(node, "link") : null;
|
||||
if (!link) return null;
|
||||
const href = link?.attrs.href;
|
||||
if (!href) return null;
|
||||
|
||||
return (
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
@@ -245,6 +246,7 @@ export function CopyLink(props: ToolProps) {
|
||||
const link = node ? findMark(node, "link") : null;
|
||||
if (!link) return null;
|
||||
const href = link?.attrs.href;
|
||||
if (!href) return null;
|
||||
|
||||
return (
|
||||
<ToolButton
|
||||
|
||||
Reference in New Issue
Block a user