Compare commits

...

47 Commits

Author SHA1 Message Date
Ammar Ahmed
2febd09613 Merge branch 'master' into fix/sync-quick-notes
Signed-off-by: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com>
2023-04-26 15:13:27 +05:00
ammarahm-ed
91138f4911 mobile: ensure full db init when sync is required 2023-04-26 15:12:29 +05:00
ammarahm-ed
f9bcfe2f7a mobile: obfuscate short emails 2023-04-26 15:02:56 +05:00
ammarahm-ed
3621f95dbc web: obfuscate short emails 2023-04-26 15:02:56 +05:00
ammarahm-ed
536dead44d mobile: always load notes on init 2023-04-26 14:59:05 +05:00
ammarahm-ed
39d74e80a9 mobile: ensure that overlay gets hidden when entering foreground 2023-04-26 14:59:05 +05:00
ammarahm-ed
46e03dd248 mobile: only show app lock for main activity 2023-04-26 14:59:05 +05:00
ammarahm-ed
152fee2c29 mobile: reload editor if rendered view lost 2023-04-26 14:59:05 +05:00
ammarahm-ed
492a4d16b2 mobile: fix note options ui 2023-04-26 14:58:37 +05:00
ammarahm-ed
3d7c1fa1e7 mobile: fix configure toolbar sheet close with swipe 2023-04-26 14:58:21 +05:00
Ammar Ahmed
8a138d960d Update apps/mobile/app/services/notifications.ts
Co-authored-by: Abdullah Atta <abdullahatta@streetwriters.co>
Signed-off-by: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com>
2023-04-26 14:57:06 +05:00
ammarahm-ed
69bb0e3656 editor: fix toolbar dropdown buttons size on mobile 2023-04-26 14:54:30 +05:00
ammarahm-ed
4875cfa108 core: duplicate note without content 2023-04-26 14:47:52 +05:00
ammarahm-ed
a28beb62c6 core: deep clone note when duplicating 2023-04-26 14:46:24 +05:00
Abdullah Atta
21c8960146 web: fix "Unauthorized" error on subscription cancel 2023-04-26 11:39:48 +05:00
ammarahm-ed
59442b9107 mobile: sync quick notes 2023-04-26 09:51:24 +05:00
Abdullah Atta
2ba638b123 web: fix font family on input field labels 2023-04-25 14:47:29 +05:00
ammarahm-ed
8548940cb9 mobile: refactor 2023-04-25 10:18:20 +05:00
Elmin Didic
909bdfa0cf docs: fix grammar & other typos in CONTRIBUTING.md (#2384)
Signed-off-by: Elmin Didic <35606145+ElminD@users.noreply.github.com>
Co-authored-by: Abdullah Atta <thecodrr@protonmail.com>
2023-04-25 10:13:56 +05:00
ammarahm-ed
bfb3c56abe mobile: remove unused patch file 2023-04-18 02:10:16 +05:00
ammarahm-ed
e06836f701 mobile: fix icon color in dark mode 2023-04-18 02:04:55 +05:00
ammarahm-ed
bc16cb79f2 mobile: fix failing tests 2023-04-18 01:54:51 +05:00
ammarahm-ed
176c46e3f2 mobile: update word count on exit 2023-04-18 01:05:14 +05:00
Abdullah Atta
af65055ce9 web: bump version to 2.4.8 2023-04-18 00:55:37 +05:00
ammarahm-ed
ad23ff19de mobile: update release notes 2023-04-18 00:55:24 +05:00
ammarahm-ed
cf65fc4f57 editor: make drag handle size dynamic 2023-04-18 00:50:41 +05:00
ammarahm-ed
9ab83e7fbb editor: reduce size of task list header 2023-04-18 00:50:20 +05:00
ammarahm-ed
1acf2aadba editor: remove top level font family on headings 2023-04-18 00:32:17 +05:00
Abdullah Atta
06833bcac9 editor: make sure editor font settings apply to all nodes 2023-04-18 00:30:40 +05:00
Ammar Ahmed
3bf6b5293a feat: Change default font size & font family in editor 2023-04-17 23:45:28 +05:00
ammarahm-ed
c40d33df37 mobile: ensure editor reloads properly 2023-04-17 23:32:28 +05:00
ammarahm-ed
fe609f8275 mobile: release v2.4.13 2023-04-17 23:08:29 +05:00
Abdullah Atta
3566f47f2d editor: all toolbars should scroll if buttons overflow 2023-04-17 22:48:43 +05:00
ammarahm-ed
4b5526dffd mobile: fix text exports 2023-04-17 22:43:56 +05:00
ammarahm-ed
4977390394 mobile: return if some days are already selected 2023-04-17 22:41:12 +05:00
ammarahm-ed
87804de452 mobile: auto select current day when repeat mode is selected 2023-04-17 22:41:12 +05:00
Ammar Ahmed
bc55d2b476 mobile: Fix toast shown forever sometimes (#2362) 2023-04-17 22:40:43 +05:00
ammarahm-ed
734e79604f mobile: use getFontById from editor 2023-04-16 01:51:49 +05:00
Abdullah Atta
a1640175e5 editor: remove unnecessary props from ToolProps 2023-04-16 01:01:01 +05:00
Abdullah Atta
7cf61570ef web: remove default-font component 2023-04-16 00:59:16 +05:00
Abdullah Atta
83762c668e web: refactor default font settings 2023-04-16 00:57:44 +05:00
Abdullah Atta
ecd4a08b1c editor: encapsulate font family utility 2023-04-16 00:57:30 +05:00
ammarahm-ed
9744679550 mobile: add support for setting default font-size & font-family 2023-04-08 01:53:46 +05:00
ammarahm-ed
9cdc502ce5 web: fix font family not applied when set on editor 2023-04-08 01:14:33 +05:00
Ammar Ahmed
300a104949 Merge branch 'master' into change-default-font
Signed-off-by: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com>
2023-04-07 23:17:23 +05:00
Muhammad Ali
df94f31998 web: added state base to default font-family and size 2023-03-22 08:38:21 +05:00
alihamuh
aec1d601a3 web: added change default fontstyle feature in the settings 2023-01-18 13:23:39 +05:00
83 changed files with 1103 additions and 819 deletions

View File

@@ -8,9 +8,9 @@ Thank you so much for considering to contribute to Notesnook! If you have no ide
Ugh! Bugs!
> A bug is when software behaves in a way that you didn't expect, and the developer didn't intend.
> A bug is when software behaves in a way you didn't expect, which the developer didn't intend.
To help us understand what's going on, we first want to **make sure you're using the latest version of Notesnook**.
To help us understand what's happening, we first want to **make sure you're using the latest version of Notesnook**.
Once you've **confirmed that the bug still exists in the latest version**, you'll want to check to make sure it's not something we already know about in the [opened GitHub issues](https://github.com/streetwriters/notesnook/issues).
@@ -30,7 +30,7 @@ Before you open a new feature request, please make sure it's not a duplicate. **
### Helping out in the issue tracker
There are always new issues getting opened that need to be triaged, sorted & organized, so the developers can easily find the most critical and/or relevant bugs to fix. Any help in this regard is appreciated.
New issues are always opened that need to be triaged, sorted & organized, so the developers can easily find the most critical and/or relevant bugs to fix. Any help in this regard is appreciated.
In addition to this, you can help out in the following ways:
@@ -62,7 +62,7 @@ Once you are done, [open a new pull request](https://docs.github.com/en/pull-req
1. Fork [the repository](https://github.com/streetwriters/notesnook) and create your branch from `master` (you can name your branch anything).
2. Run `npm run bootstrap` in the repository root.
3. If youve fixed a bug or added code that should be tested, add tests!
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`npm run test`).
5. Format your code with prettier (`npm run prettier`).
6. Make sure your code lints (`npm run lint`). Tip: `npm run linc` to only check changed files.
@@ -131,11 +131,11 @@ We use an automatic code formatter called [Prettier](https://prettier.io/). Run
Then, our linter will catch most issues that may exist in your code. You can check the status of your code styling by simply running `npm run lint`.
However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnbs Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb's Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
## Git Branch Organization
Submit all changes directly to the [`master branch`](https://github.com/streetwriters/notesnook). We dont use separate branches for development or for upcoming releases. This requires us to always keep the `master` branch in a deployable state which means:
Submit all changes directly to the [`master branch`](https://github.com/streetwriters/notesnook). We don't use separate branches for development or for upcoming releases. This requires us to always keep the `master` branch in a deployable state which means:
1. All tests must be passing at all times
2. There should be as few breaking changes as possible

View File

@@ -36,7 +36,11 @@ function getFileExtension(filename) {
var ext = /^.+\.([^.]+)$/.exec(filename);
return ext == null ? "" : ext[1];
}
/**
*
* @param {any} param0
* @returns
*/
export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
const colors = useThemeStore((state) => state.colors);
const [currentProgress, setCurrentProgress] = useAttachmentProgress(

View File

@@ -44,8 +44,10 @@ import Paragraph from "../ui/typography/paragraph";
import { LoginSteps, useLogin } from "./use-login";
function getObfuscatedEmail(email) {
if (!email) return null;
return email.replace(/(.{2})(.*)(?=@)/, function (gp1, gp2, gp3) {
if (!email) return "";
const [username, provider] = email.split("@");
if (username.length === 1) return `****@${provider}`;
return email.replace(/(.{1})(.*)(?=@)/, function (gp1, gp2, gp3) {
for (let i = 0; i < gp3.length; i++) {
gp2 += "*";
}

View File

@@ -37,6 +37,7 @@ import { useNoteStore } from "../../stores/use-notes-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { AndroidModule } from "../../utils";
import { eOpenAnnouncementDialog } from "../../utils/events";
import { getGithubVersion } from "../../utils/github-version";
import { SIZE } from "../../utils/size";
@@ -192,6 +193,11 @@ const Launcher = React.memo(
const onUnlockBiometrics = useCallback(async () => {
if (!(await BiometricService.isBiometryAvailable())) return;
if (Platform.OS === "android") {
const activityName = await AndroidModule.getActivityName();
if (activityName !== "MainActivity") return;
}
let verified = await BiometricService.validateUser(
"Unlock to access your notes",
""

View File

@@ -116,11 +116,11 @@ export const Items = ({ item, buttons, close }) => {
key={item.id}
testID={"icon-" + item.id}
customStyle={{
alignItems: "center",
alignSelf: "flex-start",
width: topBarItemWidth,
marginBottom: 10,
marginRight: isLast ? 0 : 10,
backgroundColor: "transparent"
backgroundColor: "transparent",
paddingHorizontal: 0
}}
>
<PressableButton
@@ -150,11 +150,7 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph
size={SIZE.xxs + 1}
style={{ textAlign: "center" }}
textBreakStrategy="simple"
>
<Paragraph size={SIZE.xxs + 1} style={{ textAlign: "center" }}>
{item.title}
</Paragraph>
</PressableButton>

View File

@@ -200,7 +200,8 @@ export default function ReminderSheet({
if (!_reminder) {
ToastEvent.show({
heading: "Failed to add a new reminder"
heading: "Failed to add a new reminder",
context: "local"
});
}
if (reference) {
@@ -214,7 +215,7 @@ export default function ReminderSheet({
useRelationStore.getState().update();
close?.();
} catch (e) {
ToastEvent.error(e as Error);
ToastEvent.error(e as Error, undefined, "local");
}
}
@@ -309,6 +310,16 @@ export default function ReminderSheet({
mode as keyof typeof ReminderModes
] as Reminder["mode"]
);
if (mode === "Repeat") {
setSelectedDays((days) => {
if (days.length > 0) return days;
if (days.indexOf(date.getDay()) > -1) {
return days;
}
days.push(date.getDay());
return [...days];
});
}
}}
/>
))}

View File

@@ -25,7 +25,6 @@ import Navigation from "../../../services/navigation";
import { useThemeStore } from "../../../stores/use-theme-store";
import { GROUP, SORT } from "../../../utils/constants";
import { refreshNotesPage } from "../../../utils/events";
import layoutmanager from "../../../utils/layout-manager";
import { SIZE } from "../../../utils/size";
import { Button } from "../../ui/button";
import Seperator from "../../ui/seperator";
@@ -39,7 +38,6 @@ const Sort = ({ type, screen }) => {
const updateGroupOptions = async (_groupOptions) => {
await db.settings.setGroupOptions(type, _groupOptions);
layoutmanager.withSpringAnimation(600);
setGroupOptions(_groupOptions);
setTimeout(() => {
if (screen !== "TopicSheet") Navigation.queueRoutesForUpdate(screen);

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useCallback, useEffect, useRef, useState } from "react";
import { Keyboard, TouchableOpacity, View } from "react-native";
import { TouchableOpacity, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../e2e/test.ids";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
@@ -34,24 +34,25 @@ import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
let toastMessages = [];
export const Toast = ({ context = "global" }) => {
const colors = useThemeStore((state) => state.colors);
const [keyboard, setKeyboard] = useState(false);
const [data, setData] = useState({});
const insets = useGlobalSafeAreaInsets();
const hideTimeout = useRef();
const [visible, setVisible] = useState(false);
const toastMessages = useRef([]);
const showToastFunc = useCallback(
const show = useCallback(
async (data) => {
if (!data) return;
if (data.context !== context) return;
if (toastMessages.findIndex((m) => m.message === data.message) >= 0) {
if (
toastMessages.current.findIndex((m) => m.message === data.message) >= 0
) {
return;
}
toastMessages.push(data);
if (toastMessages?.length > 1) return;
toastMessages.current.push(data);
if (toastMessages.current?.length > 1) return;
setData(data);
setVisible(true);
@@ -59,16 +60,16 @@ export const Toast = ({ context = "global" }) => {
clearTimeout(hideTimeout.current);
}
hideTimeout.current = setTimeout(() => {
hideToastFunc();
hide();
}, data.duration);
},
[context, hideToastFunc]
[context, hide]
);
const showNext = useCallback(
const next = useCallback(
(data) => {
if (!data) {
hideToastFunc();
hide();
return;
}
setData(data);
@@ -76,27 +77,28 @@ export const Toast = ({ context = "global" }) => {
clearTimeout(hideTimeout.current);
}
hideTimeout.current = setTimeout(() => {
hideToastFunc();
hide();
}, data?.duration);
},
[hideToastFunc]
[hide]
);
const hideToastFunc = useCallback(() => {
const hide = useCallback(() => {
if (hideTimeout.current) {
clearTimeout(hideTimeout.current);
}
let msg = toastMessages.length > 1 ? toastMessages.shift() : null;
let msg =
toastMessages.current.length > 1 ? toastMessages.current.shift() : null;
if (msg) {
setVisible(false);
showNext(msg);
next(msg);
setTimeout(() => {
setVisible(true);
}, 300);
} else {
setVisible(false);
toastMessages.shift();
toastMessages.current.shift();
setTimeout(() => {
setData({});
if (hideTimeout.current) {
@@ -104,44 +106,22 @@ export const Toast = ({ context = "global" }) => {
}
}, 100);
}
}, [showNext]);
const _onKeyboardShow = () => {
setKeyboard(true);
};
const _onKeyboardHide = () => {
setKeyboard(false);
};
}, [next]);
useEffect(() => {
toastMessages = [];
let sub1 = Keyboard.addListener("keyboardDidShow", _onKeyboardShow);
let sub2 = Keyboard.addListener("keyboardDidHide", _onKeyboardHide);
eSubscribeEvent(eShowToast, showToastFunc);
eSubscribeEvent(eHideToast, hideToastFunc);
eSubscribeEvent(eShowToast, show);
eSubscribeEvent(eHideToast, hide);
return () => {
if (hideTimeout.current) {
clearTimeout(hideTimeout.current);
}
toastMessages = [];
sub1?.remove();
sub2?.remove();
eUnSubscribeEvent(eShowToast, showToastFunc);
eUnSubscribeEvent(eHideToast, hideToastFunc);
toastMessages.current = [];
eUnSubscribeEvent(eShowToast, show);
eUnSubscribeEvent(eHideToast, hide);
};
}, [hideToastFunc, keyboard, showToastFunc]);
}, [hide, show]);
return (
visible && (
<TouchableOpacity
onPress={() => {
if (hideTimeout.current) {
clearTimeout(hideTimeout.current);
}
hideToastFunc();
}}
onPress={hide}
activeOpacity={1}
style={{
width: DDS.isTab ? 400 : "100%",
@@ -209,7 +189,7 @@ export const Toast = ({ context = "global" }) => {
color={colors.pri}
size={SIZE.md}
onPress={() => {
hideToastFunc();
hide();
}}
>
{data.heading}
@@ -224,7 +204,7 @@ export const Toast = ({ context = "global" }) => {
paddingRight: 10
}}
onPress={() => {
hideToastFunc();
hide();
}}
>
{data.message}

View File

@@ -19,4 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { FeatureType } from "./components/sheets/new-feature";
export const features: FeatureType[] = [];
export const features: FeatureType[] = [
{
title: "Default font size & font family",
body: "Now you can set default font size and font family in editor that will be used across all your new and old notes."
}
];

View File

@@ -613,7 +613,7 @@ export const useActions = ({ close = () => null, item }) => {
},
{
id: "pin",
title: item.pinned ? "Unpin" : "Pin",
title: "Pin",
icon: item.pinned ? "pin-off-outline" : "pin-outline",
func: pinItem,
close: false,
@@ -623,7 +623,7 @@ export const useActions = ({ close = () => null, item }) => {
},
{
id: "favorite",
title: !item.favorite ? "Favorite" : "Unfavorite",
title: "Favorite",
icon: item.favorite ? "star-off" : "star-outline",
func: addToFavorites,
close: false,

View File

@@ -571,8 +571,8 @@ export const useAppEvents = () => {
if (notesAddedFromIntent || shareExtensionOpened) {
let id = useEditorStore.getState().currentEditingNote;
let note = id && db.notes.note(id).data;
eSendEvent("loadingNote", note);
eSendEvent("webview_reset");
setTimeout(() => eSendEvent("loadingNote", note), 1);
MMKV.removeItem("shareExtensionOpened");
}
} catch (e) {

View File

@@ -17,35 +17,46 @@ 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 { useEffect, useState } from "react";
import { useState } from "react";
import { useAttachmentStore } from "../stores/use-attachment-store";
export const useAttachmentProgress = (attachment, encryption) => {
type AttachmentProgress = {
type: string;
value?: number;
percent?: string;
};
export const useAttachmentProgress = (
attachment: any,
encryption?: boolean
) => {
const progress = useAttachmentStore((state) => state.progress);
const [currentProgress, setCurrentProgress] = useState(
const [currentProgress, setCurrentProgress] = useState<
AttachmentProgress | undefined
>(
encryption
? {
type: "encrypt"
}
: null
: undefined
);
useEffect(() => {
let prog = progress[attachment.metadata.hash];
if (prog) {
let type = prog.type;
let loaded = prog.type === "download" ? prog.recieved : prog.sent;
prog = loaded / prog.total;
prog = (prog * 100).toFixed(0);
setCurrentProgress({
value: prog,
percent: prog + "%",
type: type
});
} else {
setCurrentProgress(null);
}
}, [attachment.metadata.hash, progress]);
const attachmentProgress = progress?.[attachment.metadata.hash];
if (attachmentProgress) {
const type = attachmentProgress.type;
const loaded =
attachmentProgress.type === "download"
? attachmentProgress.recieved
: attachmentProgress.sent;
const value = loaded / attachmentProgress.total;
setCurrentProgress({
value: value * 100,
percent: (value * 100).toFixed(0) + "%",
type: type
});
} else {
setCurrentProgress(undefined);
}
return [currentProgress, setCurrentProgress];
};

View File

@@ -1,61 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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 React, { useCallback, useEffect } from "react";
import BiometicService from "../services/biometrics";
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
import { db } from "../common/database";
const VaultStatusCache = {
exists: false,
biometryEnrolled: false,
isBiometryAvailable: false
};
export const useVaultStatus = () => {
const [vaultStatus, setVaultStatus] = React.useState(VaultStatusCache);
const checkVaultStatus = useCallback(() => {
db.vault.exists().then(async (exists) => {
let available = await BiometicService.isBiometryAvailable();
let fingerprint = await BiometicService.hasInternetCredentials();
if (
VaultStatusCache.exists === exists &&
VaultStatusCache.biometryEnrolled === fingerprint &&
VaultStatusCache.isBiometryAvailable === available
)
return;
setVaultStatus({
exists: exists,
biometryEnrolled: fingerprint,
isBiometryAvailable: available ? true : false
});
});
}, []);
useEffect(() => {
checkVaultStatus();
eSubscribeEvent("vaultUpdated", () => checkVaultStatus());
return () => {
eUnSubscribeEvent("vaultUpdated", () => checkVaultStatus());
};
}, [checkVaultStatus]);
return vaultStatus;
};

View File

@@ -10,7 +10,7 @@
"buffer": "^6.0.3",
"dayjs": "^1.10.4",
"entities": "^3.0.1",
"html-to-text": "8.1.0",
"html-to-text": "9.0.5",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.18",

View File

@@ -24,6 +24,7 @@ import React, {
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState
} from "react";
import { Platform, ViewStyle } from "react-native";
@@ -89,7 +90,7 @@ const Editor = React.memo(
noToolbar,
noHeader
});
const renderKey = useRef(`editor-0`);
useImperativeHandle(ref, () => ({
get: () => editor
}));
@@ -124,6 +125,8 @@ const Editor = React.memo(
);
const onError = useCallback(() => {
renderKey.current =
renderKey.current === `editor-0` ? `editor-1` : `editor-0`;
editor.setLoading(true);
setTimeout(() => editor.setLoading(false), 10);
}, [editor]);
@@ -152,6 +155,7 @@ const Editor = React.memo(
testID={notesnook.editor.id}
ref={editor.ref}
onLoad={editor.onLoad}
key={renderKey.current}
onRenderProcessGone={onError}
nestedScrollEnabled
onError={onError}

View File

@@ -106,6 +106,7 @@ typeof globalThis.editorTitle !== "undefined" && editorTitle.current && editorTi
if (editorController.content) editorController.content.current = null;
editorController.onUpdate();
editorController.setTitle(null);
editorController.countWords(0);
typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"",saved:""});
`
);

View File

@@ -48,6 +48,8 @@ export type Settings = {
keyboardShown?: boolean;
doubleSpacedLines?: boolean;
corsProxy: string;
fontSize: string;
fontFamily: string;
};
export type EditorProps = {

View File

@@ -136,6 +136,13 @@ export const useEditorEvents = (
const doubleSpacedLines = useSettingStore(
(state) => state.settings?.doubleSpacedLines
);
const defaultFontSize = useSettingStore(
(state) => state.settings.defaultFontSize
);
const defaultFontFamily = useSettingStore(
(state) => state.settings.defaultFontFamily
);
const tools = useDragState((state) => state.data);
useEffect(() => {
@@ -164,7 +171,9 @@ export const useEditorEvents = (
noHeader: noHeader,
noToolbar: readonly || editorPropReadonly || noToolbar,
doubleSpacedLines: doubleSpacedLines,
corsProxy: corsProxy
corsProxy: corsProxy,
fontSize: defaultFontSize,
fontFamily: defaultFontFamily
});
}, [
fullscreen,
@@ -179,7 +188,9 @@ export const useEditorEvents = (
editorPropReadonly,
noHeader,
noToolbar,
corsProxy
corsProxy,
defaultFontSize,
defaultFontFamily
]);
const onBackPress = useCallback(async () => {

View File

@@ -580,22 +580,21 @@ export const useEditor = (
const onReady = useCallback(async () => {
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
overlay(true);
setLoading(true);
eSendEvent("webview_reset");
} else {
isDefaultEditor && restoreEditorState();
}
}, [overlay, isDefaultEditor, restoreEditorState]);
}, [isDefaultEditor, restoreEditorState]);
useEffect(() => {
state.current.saveCount = 0;
async () => {
(async () => {
await commands.setSessionId(sessionIdRef.current);
if (sessionIdRef.current) {
if (!state.current?.ready) return;
await onReady();
}
};
})();
}, [sessionId, loading, commands, onReady]);
const onLoad = useCallback(async () => {
@@ -636,6 +635,7 @@ export const useEditor = (
saveContent,
onContentChanged,
editorId: editorId,
markImageLoaded
markImageLoaded,
overlay
};
};

View File

@@ -51,6 +51,7 @@ export const EditorWrapper = ({ width }) => {
if (editorState().movedAway) return;
if (state === "active") {
editorController.current.onReady();
editorController.current.overlay(false);
}
};

View File

@@ -26,6 +26,7 @@ import { Licenses } from "./licenses";
import SoundPicker from "./sound-picker";
import { Subscription } from "./subscription";
import { TrashIntervalSelector } from "./trash-interval-selector";
import { FontSelector } from "./font-selector";
export const components: { [name: string]: ReactElement } = {
colorpicker: <AccentColorPicker />,
homeselector: <HomagePageSelector />,
@@ -35,5 +36,6 @@ export const components: { [name: string]: ReactElement } = {
"debug-logs": <DebugLogs />,
"sound-picker": <SoundPicker />,
licenses: <Licenses />,
"trash-interval-selector": <TrashIntervalSelector />
"trash-interval-selector": <TrashIntervalSelector />,
"font-selector": <FontSelector />
};

View File

@@ -20,8 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { ToolId } from "@notesnook/editor/dist/toolbar";
import React, { RefObject } from "react";
import { View } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import { ScrollView } from "react-native-gesture-handler";
import { PressableButton } from "../../../components/ui/pressable";
import { SvgView } from "../../../components/ui/svg";
import Paragraph from "../../../components/ui/typography/paragraph";
@@ -34,13 +32,14 @@ import {
getToolIcon,
getUngroupedTools
} from "./toolbar-definition";
import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
export default function ToolSheet({
group,
fwdRef
}: {
group: DraggableItem;
fwdRef: RefObject<ActionSheet>;
fwdRef: RefObject<ActionSheetRef>;
}) {
const colors = useThemeStore((state) => state.colors);
const data = useDragState((state) => state.data);
@@ -50,6 +49,7 @@ export default function ToolSheet({
(item: ToolId) => {
const tool = findToolById(item);
const iconSvgString = tool ? getToolIcon(tool.icon as ToolId) : null;
if (item === "none") return;
return (
<PressableButton
key={item}
@@ -109,12 +109,7 @@ export default function ToolSheet({
padding: 12
}}
>
<ScrollView
onMomentumScrollEnd={() => {
fwdRef.current?.handleChildScrollEnd();
}}
nestedScrollEnabled={true}
>
<ScrollView nestedScrollEnabled={true}>
{!ungrouped || ungrouped.length === 0 ? (
<Paragraph
style={{

View File

@@ -0,0 +1,110 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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 React, { useRef, useState } from "react";
import { View } from "react-native";
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { PressableButton } from "../../components/ui/pressable";
import Paragraph from "../../components/ui/typography/paragraph";
import SettingsService from "../../services/settings";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
export const FontSelector = () => {
const colors = useThemeStore((state) => state.colors);
const defaultFontFamily = useSettingStore(
(state) => state.settings.defaultFontFamily
);
const menuRef = useRef();
const [width, setWidth] = useState(0);
const onChange = (item) => {
menuRef.current?.hide();
SettingsService.set({
defaultFontFamily: item
});
};
return (
<View
onLayout={(event) => {
setWidth(event.nativeEvent.layout.width);
}}
style={{
width: "100%"
}}
>
<Menu
ref={menuRef}
animationDuration={200}
style={{
borderRadius: 5,
backgroundColor: colors.bg,
width: width,
marginTop: 60
}}
onRequestClose={() => {
menuRef.current?.hide();
}}
anchor={
<PressableButton
onPress={async () => {
menuRef.current?.show();
}}
type="grayBg"
customStyle={{
flexDirection: "row",
alignItems: "center",
marginTop: 10,
width: "100%",
justifyContent: "space-between",
padding: 12
}}
>
<Paragraph>{getFontById(defaultFontFamily).title}</Paragraph>
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
</PressableButton>
}
>
{getFonts().map((item) => (
<MenuItem
key={item.id}
onPress={async () => {
onChange(item.id);
}}
style={{
backgroundColor:
defaultFontFamily === item.id ? colors.nav : "transparent",
width: "100%",
maxWidth: width
}}
textStyle={{
fontSize: SIZE.md,
color: defaultFontFamily === item.id ? colors.accent : colors.pri
}}
>
{item.title}
</MenuItem>
))}
</Menu>
</View>
);
};

View File

@@ -37,6 +37,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { components } from "./components";
import { RouteParams, SettingSection } from "./types";
import { IconButton } from "../../components/ui/icon-button";
const _SectionItem = ({ item }: { item: SettingSection }) => {
const colors = useThemeStore((state) => state.colors);
@@ -64,6 +65,12 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
backgroundColor: colors.errorBg
}
: {};
const updateInput = (value: any) => {
inputRef?.current?.setNativeProps({
text: value + ""
});
};
return isHidden ? null : (
<PressableButton
disabled={item.type === "component"}
@@ -190,6 +197,95 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
defaultValue={item.inputProperties?.defaultValue}
/>
)}
{item.type === "input-selector" && (
<View
style={{
flexDirection: "row",
alignItems: "center",
marginTop: 12
}}
>
<IconButton
name="minus"
color={colors.pri}
onPress={() => {
const rawValue = SettingsService.get()[
item.property as keyof SettingStore["settings"]
] as string;
if (rawValue) {
const currentValue = parseInt(rawValue);
if (currentValue <= 0) return;
const nextValue = currentValue - 1;
SettingsService.set({
[item.property as string]: nextValue
});
updateInput(nextValue);
}
}}
size={SIZE.xl}
/>
<Input
{...item.inputProperties}
onSubmit={(e) => {
if (e.nativeEvent.text) {
SettingsService.set({
[item.property as string]: e.nativeEvent.text
});
}
item.inputProperties?.onSubmitEditing?.(e);
}}
onChangeText={(text) => {
if (text) {
if (item.minInputValue) {
text =
parseInt(text) < item.minInputValue
? item.minInputValue + ""
: text;
}
SettingsService.set({
[item.property as string]: text
});
}
item.inputProperties?.onSubmitEditing?.(text as any);
}}
keyboardType="decimal-pad"
containerStyle={{
width: 45
}}
wrapperStyle={{
maxWidth: 45,
marginBottom: 0,
marginHorizontal: 6
}}
fwdRef={inputRef}
onLayout={() => {
if (item.property) {
updateInput(SettingsService.get()[item.property]);
}
}}
defaultValue={item.inputProperties?.defaultValue}
/>
<IconButton
name="plus"
color={colors.pri}
onPress={() => {
const rawValue = SettingsService.get()[
item.property as keyof SettingStore["settings"]
] as string;
if (rawValue) {
const currentValue = parseInt(rawValue);
const nextValue = currentValue + 1;
SettingsService.set({
[item.property as string]: nextValue
});
updateInput(nextValue);
}
}}
size={SIZE.xl}
/>
</View>
)}
</View>
</View>

View File

@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import notifee from "@notifee/react-native";
import dayjs from "dayjs";
import React from "react";
import { Linking, Platform } from "react-native";
@@ -450,13 +451,13 @@ export const settingsGroups: SettingSection[] = [
},
{
id: "customize",
name: "Customize",
name: "Customization",
sections: [
{
id: "personalization",
type: "screen",
name: "Theme",
description: "Change app look and feel",
description: "Change app look and feel with color themes",
icon: "shape",
sections: [
{
@@ -514,7 +515,7 @@ export const settingsGroups: SettingSection[] = [
id: "behaviour",
type: "screen",
name: "Behaviour",
description: "Change app homepage",
description: "Change how the app behaves in different situations",
sections: [
{
id: "default-home",
@@ -532,6 +533,63 @@ export const settingsGroups: SettingSection[] = [
component: "trash-interval-selector"
}
]
},
{
id: "editor",
name: "Editor",
type: "screen",
icon: "note-edit-outline",
description: "Customize the editor to fit your needs",
sections: [
{
id: "configure-toolbar",
type: "screen",
name: "Configure toolbar",
description: "Make the toolbar adaptable to your needs.",
component: "configuretoolbar"
},
{
id: "reset-toolbar",
name: "Reset toolbar",
description: "Reset toolbar configuration to default",
modifer: () => {
useDragState.getState().setPreset("default");
}
},
{
id: "double-spaced-lines",
name: "Use double spaced lines",
description:
"New lines will be double spaced (old ones won't be affected).",
type: "switch",
property: "doubleSpacedLines",
icon: "format-line-spacing",
onChange: () => {
ToastEvent.show({
heading: "Line spacing changed",
type: "success"
});
}
},
{
id: "default-font-size",
name: "Default font size",
description: "Set the default font size in editor",
type: "input-selector",
minInputValue: 8,
icon: "format-size",
property: "defaultFontSize"
},
{
id: "default-font-family",
name: "Default font family",
description: "Set the default font family in editor",
type: "component",
icon: "format-font",
property: "defaultFontFamily",
component: "font-selector"
}
]
}
]
},
@@ -928,42 +986,6 @@ export const settingsGroups: SettingSection[] = [
}
]
},
{
id: "editor",
name: "Editor",
sections: [
{
id: "configure-toolbar",
type: "screen",
name: "Configure toolbar",
description: "Make the toolbar adaptable to your needs.",
component: "configuretoolbar"
},
{
id: "reset-toolbar",
name: "Reset toolbar",
description: "Reset toolbar configuration to default",
modifer: () => {
useDragState.getState().setPreset("default");
}
},
{
id: "double-spaced-lines",
name: "Use double spaced lines",
description:
"New lines will be double spaced (old ones won't be affected).",
type: "switch",
property: "doubleSpacedLines",
icon: "format-line-spacing",
onChange: () => {
ToastEvent.show({
heading: "Line spacing changed",
type: "success"
});
}
}
]
},
{
id: "help-support",
name: "Help and support",

View File

@@ -22,7 +22,14 @@ import { Settings } from "../../stores/use-setting-store";
export type SettingSection = {
id: string;
type?: "screen" | "switch" | "component" | "danger" | "input";
type?:
| "screen"
| "switch"
| "component"
| "danger"
| "input"
| "input-selector"
| "dropdown-selector";
name?: string | ((current?: unknown) => string);
description?: string | ((current: unknown) => string);
icon?: string;
@@ -35,6 +42,8 @@ export type SettingSection = {
hidden?: (current: unknown) => boolean;
onChange?: (property: boolean) => void;
inputProperties?: TextInput["props"];
options?: any[];
minInputValue?: number;
};
export type SettingsGroup = {

View File

@@ -86,8 +86,9 @@ async function getNextMonthlyReminderDate(
}
async function initDatabase(notes = true) {
if (db.isInitialized) return;
await db.initCollections();
if (!db.isInitialized) {
await db.initCollections();
}
if (notes) {
await db.notes?.init();
}
@@ -202,14 +203,15 @@ const onEvent = async ({ type, detail }: Event) => {
reply_button_text: "Take note",
reply_placeholder_text: "Write something..."
});
await initDatabase(false);
if (!db.isInitialized) await db.init();
await db.notes?.init();
await db.notes?.add({
content: {
type: "tiptap",
data: `<p>${input} </p>`
}
});
await db.notes?.init();
await db.sync(false, false);
useNoteStore.getState().setNotes();
break;
}

View File

@@ -27,14 +27,6 @@ import { DatabaseLogger } from "../common/database/index";
import { ToastEvent } from "./event-manager";
import SettingsService from "./settings";
NetInfo.configure({
reachabilityUrl: "https://notesnook.com",
reachabilityTest: (response) => {
if (!response) return false;
return response?.status >= 200 && response?.status < 300;
}
});
export const ignoredMessages = [
"Sync already running",
"Not allowed to start service intent",

View File

@@ -24,7 +24,6 @@ import { db } from "../common/database";
import { MMKV } from "../common/database/mmkv";
import PremiumService from "../services/premium";
import { SUBSCRIPTION_STATUS } from "../utils/constants";
import layoutmanager from "../utils/layout-manager";
export interface MessageStore extends State {
message: Message;
setMessage: (message: Message) => void;
@@ -96,13 +95,7 @@ export const useMessageStore = create<MessageStore>((set, get) => ({
icon: "account-outline"
},
setMessage: (message) => {
setTimeout(() => {
if (get().message.visible || message.visible) {
layoutmanager.withAnimation();
}
set({ message: { ...message } });
}, 1);
set({ message: { ...message } });
},
announcements: [],
remove: async (id) => {

View File

@@ -69,6 +69,7 @@ export type RouteParams = {
AppLock: AppLockRouteParams;
Auth: AuthParams;
Reminders: GenericRouteParam;
SettingsGroup: GenericRouteParam;
};
export type RouteName = keyof RouteParams;

View File

@@ -73,6 +73,8 @@ export type Settings = {
corsProxy: string;
disableRealtimeSync?: boolean;
notificationSound?: Sound & { platform: PlatformOSType };
defaultFontSize: string;
defaultFontFamily: string;
};
type DimensionsType = {
@@ -149,7 +151,9 @@ export const useSettingStore = create<SettingStore>((set) => ({
defaultSnoozeTime: "5",
corsProxy: "https://cors.notesnook.com",
reminderNotificationMode: "urgent",
notificationSound: undefined
notificationSound: undefined,
defaultFontFamily: "sans-serif",
defaultFontSize: "16"
},
sheetKeyboardHandler: true,
fullscreen: false,

View File

@@ -27,7 +27,6 @@ import { db } from "../common/database";
import { tabBarRef } from "./global-refs";
let prevTarget = null;
let htmlToText;
export const TOOLTIP_POSITIONS = {
LEFT: 1,
@@ -171,3 +170,8 @@ export function showTooltip(event, text, position = 2) {
clickToHide: true
});
}
export function toTitleCase(value) {
if (!value) return;
return value.slice(0, 1).toUpperCase() + value.slice(1);
}

View File

@@ -46,18 +46,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* @return {String} Sanitized filename
*/
var illegalRe = /[/?<>\\:*|"]/g;
const illegalRe = /[/?<>\\:*|"]/g;
//var controlRe = /[x00-x1f\x80-\x9f]/g;
var reservedRe = /^\.+$/;
var windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
var windowsTrailingRe = /[. ]+$/;
var whitespace = /\s+/g;
const reservedRe = /^\.+$/;
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
const windowsTrailingRe = /[. ]+$/;
const whitespace = /\s+/g;
function sanitize(input, replacement) {
function sanitize(input: string, replacement: string) {
if (typeof input !== "string") {
throw new Error("Input must be string");
}
var sanitized = input
const sanitized = input
.replace(whitespace, replacement)
.replace(illegalRe, replacement)
.replace(reservedRe, replacement)
@@ -67,7 +67,10 @@ function sanitize(input, replacement) {
return sanitized.slice(0, 254).toLowerCase();
}
export function sanitizeFilename(input, options) {
var replacement = (options && options.replacement) || "";
export function sanitizeFilename(
input: string,
options: { replacement: string }
) {
const replacement = (options && options.replacement) || "";
return sanitize(input, replacement);
}

View File

@@ -48,7 +48,7 @@ describe("NOTE TESTS", () => {
await prepare();
let note = await createNote();
await tapById(notesnook.listitem.menu);
await visibleByText(note.body);
await visibleByText("Created at:");
});
it("Favorite and unfavorite a note", async () => {
@@ -124,8 +124,9 @@ describe("NOTE TESTS", () => {
await prepare();
await createNote();
await tapById(notesnook.listitem.menu);
await tapById("icon-delete");
await tapById("icon-trash");
await navigate("Trash");
await sleep(500);
await tapById(notesnook.listitem.menu);
await tapByText("Restore note");
await device.pressBack();

View File

@@ -56,7 +56,7 @@ async function createNotebook(
await tapById("topic-add-button");
}
}
await tapByText("Create notebook");
await tapByText("Save");
await sleep(500);
}
@@ -120,7 +120,7 @@ describe("NOTEBOOKS", () => {
await visibleByText(note.body);
});
it("Add new topic to notebook", async () => {
it.only("Add new topic to notebook", async () => {
await prepare();
await navigate("Notebooks");
await sleep(500);
@@ -133,7 +133,7 @@ describe("NOTEBOOKS", () => {
await elementById("input-title").typeText("Topic");
await tapByText("Add");
await sleep(500);
await visibleById("topic-sheet-item-0");
await tapByText("Topic");
});
it("Edit topic", async () => {
@@ -146,7 +146,6 @@ describe("NOTEBOOKS", () => {
await sleep(500);
await tapByText("Notebook 1");
await sleep(300);
await visibleById("topic-sheet-item-0");
await tapById(notesnook.ids.notebook.menu);
await tapByText("Edit topic");
await elementById("input-title").typeText(" (edited)");
@@ -254,7 +253,7 @@ describe("NOTEBOOKS", () => {
"Topic 2"
);
await tapById("topic-add-button");
await tapByText("Save changes");
await tapByText("Save");
await sleep(500);
await visibleByText("Notebook 1 (Edited)");
await visibleByText("Description of Notebook 1 (Edited)");
@@ -274,7 +273,7 @@ describe("NOTEBOOKS", () => {
await tapById(notesnook.ids.notebook.menu);
await tapByText("Move to trash");
await sleep(2000);
await tapByText("No");
await tapByText("Delete");
await sleep(4000);
await navigate("Trash");
await visibleByText("Notebook 1");
@@ -296,7 +295,9 @@ describe("NOTEBOOKS", () => {
await tapById(notesnook.ids.notebook.menu);
await tapByText("Move to trash");
await sleep(2000);
await tapByText("Yes");
await tapByText("Move all notes in this notebook to trash");
await sleep(500);
await tapByText("Delete");
await sleep(4000);
await navigate("Trash");
await visibleByText("Notebook 1");
@@ -319,7 +320,9 @@ describe("NOTEBOOKS", () => {
await tapById(notesnook.ids.notebook.menu);
await tapByText("Delete topic");
await sleep(2000);
await tapByText("Yes");
await tapByText("Move all notes in this topic to trash");
await sleep(500);
await tapByText("Delete");
await device.pressBack();
await sleep(4000);
await navigate("Trash");

View File

@@ -164,7 +164,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true
versionCode 2043
versionCode 2044
versionName getNpmVersion()
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

View File

@@ -4,6 +4,7 @@ package com.streetwriters.notesnook;
import android.graphics.Color;
import android.view.WindowManager;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -36,6 +37,16 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
}
}
@ReactMethod
public void getActivityName(Promise promise) {
try {
promise.resolve(getCurrentActivity().getClass().getSimpleName());
} catch (Exception e) {
promise.resolve(null);
}
}
@ReactMethod
public void setSecureMode(final boolean mode) {

View File

@@ -1,6 +1,10 @@
- Fixed text exports not following line spacing settings
- Fixed tags are not updated in list after renaming
- Fixed a sync issue where notes marked as local only would get deleted sometimes
- Fixed a bug where opening a note from search then closing it would cause a crash
- Added default font size & font family settings
- Redesign reminder/notebook sheets to improve UX
- Fixed an issue causing sync to fail
- Fix tag suggestions in share extension
- Fix app font sizes too small in some places
- Improved mobile editor performance on low-end devices
- Fix pin to notifications not working
- Bug fixes and performance improvements
Thank you for using Notesnook!

View File

@@ -993,7 +993,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1067,7 +1067,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1097,7 +1097,7 @@
CODE_SIGN_ENTITLEMENTS = Notesnook/Notesnook.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@@ -1170,7 +1170,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1328,7 +1328,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1340,7 +1340,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1370,7 +1370,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1382,7 +1382,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1411,7 +1411,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1485,7 +1485,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1515,7 +1515,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 2035;
CURRENT_PROJECT_VERSION = 2036;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 53CWBG3QUC;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
@@ -1589,7 +1589,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.4.12;
MARKETING_VERSION = 2.4.13;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -1,6 +1,10 @@
- Fixed text exports not following line spacing settings
- Fixed tags are not updated in list after renaming
- Fixed a sync issue where notes marked as local only would get deleted sometimes
- Fixed a bug where opening a note from search then closing it would cause a crash
- Added default font size & font family settings
- Redesign reminder/notebook sheets to improve UX
- Fixed an issue causing sync to fail
- Fix tag suggestions in share extension
- Fix app font sizes too small in some places
- Improved mobile editor performance on low-end devices
- Fix pin to notifications not working
- Bug fixes and performance improvements
Thank you for using Notesnook!

View File

@@ -86,7 +86,17 @@ module.exports = (env) => {
"@notesnook": path.join(__dirname, "../../../packages"),
"@streetwriters/showdown": path.join(__dirname, "../node_modules/@streetwriters/showdown"),
"qclone": path.join(__dirname, "../node_modules/qclone"),
"@notifee/react-native": path.join(__dirname, "../node_modules/@ammarahmed/notifee-react-native")
"@notifee/react-native": path.join(__dirname, "../node_modules/@ammarahmed/notifee-react-native"),
"html-to-text": path.join(__dirname, "../node_modules/html-to-text"),
"leac": path.join(__dirname, "../node_modules/leac"),
"parseley": path.join(__dirname, "../node_modules/parseley"),
"htmlparser2": path.join(__dirname, "../node_modules/htmlparser2"),
"selderee": path.join(__dirname, "../node_modules/selderee"),
"minimist": path.join(__dirname, "../node_modules/minimist"),
"entities": path.join(__dirname, "../node_modules/entities"),
"deepmerge": path.join(__dirname, "../node_modules/deepmerge"),
"@selderee/plugin-htmlparser2": path.join(__dirname, "../node_modules/@selderee/plugin-htmlparser2"),
"peberminta": path.join(__dirname, "../node_modules/peberminta"),
},
},
/**

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/mobile",
"version": "2.4.12",
"version": "2.4.13",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/mobile",
"version": "2.4.12",
"version": "2.4.13",
"license": "GPL-3.0-or-later",
"workspaces": [
"native/",
@@ -35,7 +35,7 @@
"dayjs": "^1.10.4",
"entities": "^3.0.1",
"fflate": "^0.7.3",
"html-to-text": "8.1.0",
"html-to-text": "9.0.5",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.18",
@@ -5620,12 +5620,12 @@
}
},
"node_modules/@selderee/plugin-htmlparser2": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz",
"integrity": "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
"dependencies": {
"domhandler": "^4.2.0",
"selderee": "^0.6.0"
"domhandler": "^5.0.3",
"selderee": "^0.11.0"
},
"funding": {
"url": "https://ko-fi.com/killymxi"
@@ -8142,57 +8142,6 @@
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-select/node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/css-select/node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/css-select/node_modules/domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.1"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/css-select/node_modules/entities": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/css-tree": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
@@ -8288,9 +8237,9 @@
"dev": true
},
"node_modules/deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"engines": {
"node": ">=0.10.0"
}
@@ -8573,11 +8522,6 @@
"node": ">=8"
}
},
"node_modules/discontinuous-range": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
},
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -8591,22 +8535,25 @@
}
},
"node_modules/dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/dom-serializer/node_modules/entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
@@ -8628,11 +8575,11 @@
]
},
"node_modules/domhandler": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.2.0"
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
@@ -8642,13 +8589,13 @@
}
},
"node_modules/domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
"dependencies": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.1"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
@@ -10967,14 +10914,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"bin": {
"he": "bin/he"
}
},
"node_modules/hermes-engine": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz",
@@ -11024,28 +10963,24 @@
"dev": true
},
"node_modules/html-to-text": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.1.0.tgz",
"integrity": "sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q==",
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
"dependencies": {
"@selderee/plugin-htmlparser2": "^0.6.0",
"deepmerge": "^4.2.2",
"he": "^1.2.0",
"htmlparser2": "^6.1.0",
"minimist": "^1.2.5",
"selderee": "^0.6.0"
},
"bin": {
"html-to-text": "bin/cli.js"
"@selderee/plugin-htmlparser2": "^0.11.0",
"deepmerge": "^4.3.1",
"dom-serializer": "^2.0.0",
"htmlparser2": "^8.0.2",
"selderee": "^0.11.0"
},
"engines": {
"node": ">=10.23.2"
"node": ">=14"
}
},
"node_modules/htmlparser2": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
@@ -11054,16 +10989,19 @@
}
],
"dependencies": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"domutils": "^2.5.2",
"entities": "^2.0.0"
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"node_modules/htmlparser2/node_modules/entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
@@ -14377,6 +14315,14 @@
"node": ">=6"
}
},
"node_modules/leac": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
"funding": {
"url": "https://ko-fi.com/killymxi"
}
},
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -16188,11 +16134,6 @@
"node": "*"
}
},
"node_modules/moo": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -16298,27 +16239,6 @@
"ncp": "bin/ncp"
}
},
"node_modules/nearley": {
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
"integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
"dependencies": {
"commander": "^2.19.0",
"moo": "^0.5.0",
"railroad-diagrams": "^1.0.0",
"randexp": "0.4.6"
},
"bin": {
"nearley-railroad": "bin/nearley-railroad.js",
"nearley-test": "bin/nearley-test.js",
"nearley-unparse": "bin/nearley-unparse.js",
"nearleyc": "bin/nearleyc.js"
},
"funding": {
"type": "individual",
"url": "https://nearley.js.org/#give-to-nearley"
}
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -16977,12 +16897,12 @@
}
},
"node_modules/parseley": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.7.0.tgz",
"integrity": "sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.0.tgz",
"integrity": "sha512-uLqDm6IQVb6m50a3dIxF66hI8VWr7wFDYUULtHa1ITRh9mwYIXzFpPTkPM66Cm5V0t+bMyeSHgUCGzoXTV96LQ==",
"dependencies": {
"moo": "^0.5.1",
"nearley": "^2.20.1"
"leac": "^0.6.0",
"peberminta": "^0.9.0"
},
"funding": {
"url": "https://ko-fi.com/killymxi"
@@ -17069,6 +16989,14 @@
"node": ">=8"
}
},
"node_modules/peberminta": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
"funding": {
"url": "https://ko-fi.com/killymxi"
}
},
"node_modules/phin": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
@@ -17807,31 +17735,6 @@
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"node_modules/railroad-diagrams": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
"integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A=="
},
"node_modules/randexp": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
"integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
"dependencies": {
"discontinuous-range": "1.0.0",
"ret": "~0.1.10"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/randexp/node_modules/ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"engines": {
"node": ">=0.12"
}
},
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -19159,11 +19062,11 @@
"integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w=="
},
"node_modules/selderee": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.6.0.tgz",
"integrity": "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
"dependencies": {
"parseley": "^0.7.0"
"parseley": "^0.12.0"
},
"funding": {
"url": "https://ko-fi.com/killymxi"
@@ -24311,7 +24214,7 @@
"dayjs": "^1.10.4",
"entities": "^3.0.1",
"fflate": "^0.7.3",
"html-to-text": "8.1.0",
"html-to-text": "9.0.5",
"phone": "^3.1.14",
"qclone": "^1.2.0",
"react-native-actions-sheet": "0.9.0-alpha.18",
@@ -25573,12 +25476,12 @@
"integrity": "sha512-1k57PXJIfhZrjA4ZQr+goTEYer8MBhe1At6XjVYJq1oBuhG/CIu0gX1EH9fU9exC65e5uDs/zAwjl6Ps+3lCgg=="
},
"@selderee/plugin-htmlparser2": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz",
"integrity": "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
"requires": {
"domhandler": "^4.2.0",
"selderee": "^0.6.0"
"domhandler": "^5.0.3",
"selderee": "^0.11.0"
}
},
"@shopify/flash-list": {
@@ -27520,41 +27423,6 @@
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"dependencies": {
"dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
}
},
"domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"requires": {
"domelementtype": "^2.3.0"
}
},
"domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
"requires": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.1"
}
},
"entities": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
}
}
},
"css-tree": {
@@ -27627,9 +27495,9 @@
"dev": true
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="
},
"defaults": {
"version": "1.0.4",
@@ -27823,11 +27691,6 @@
"path-type": "^4.0.0"
}
},
"discontinuous-range": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
},
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -27838,19 +27701,19 @@
}
},
"dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"dependencies": {
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
}
}
},
@@ -27865,21 +27728,21 @@
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
},
"domhandler": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"requires": {
"domelementtype": "^2.2.0"
"domelementtype": "^2.3.0"
}
},
"domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0"
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.1"
}
},
"dooboolab-welcome": {
@@ -29594,11 +29457,6 @@
"type-fest": "^0.8.0"
}
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"hermes-engine": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz",
@@ -29645,33 +29503,32 @@
"dev": true
},
"html-to-text": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.1.0.tgz",
"integrity": "sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q==",
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
"requires": {
"@selderee/plugin-htmlparser2": "^0.6.0",
"deepmerge": "^4.2.2",
"he": "^1.2.0",
"htmlparser2": "^6.1.0",
"minimist": "^1.2.5",
"selderee": "^0.6.0"
"@selderee/plugin-htmlparser2": "^0.11.0",
"deepmerge": "^4.3.1",
"dom-serializer": "^2.0.0",
"htmlparser2": "^8.0.2",
"selderee": "^0.11.0"
}
},
"htmlparser2": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"domutils": "^2.5.2",
"entities": "^2.0.0"
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
},
"dependencies": {
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
}
}
},
@@ -32133,6 +31990,11 @@
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
},
"leac": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="
},
"leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -33541,11 +33403,6 @@
"dev": true,
"optional": true
},
"moo": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -33632,17 +33489,6 @@
"dev": true,
"optional": true
},
"nearley": {
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
"integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
"requires": {
"commander": "^2.19.0",
"moo": "^0.5.0",
"railroad-diagrams": "^1.0.0",
"randexp": "0.4.6"
}
},
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -34119,12 +33965,12 @@
}
},
"parseley": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.7.0.tgz",
"integrity": "sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.0.tgz",
"integrity": "sha512-uLqDm6IQVb6m50a3dIxF66hI8VWr7wFDYUULtHa1ITRh9mwYIXzFpPTkPM66Cm5V0t+bMyeSHgUCGzoXTV96LQ==",
"requires": {
"moo": "^0.5.1",
"nearley": "^2.20.1"
"leac": "^0.6.0",
"peberminta": "^0.9.0"
}
},
"parseurl": {
@@ -34184,6 +34030,11 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"peberminta": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="
},
"phin": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
@@ -34734,27 +34585,6 @@
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"railroad-diagrams": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
"integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A=="
},
"randexp": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
"integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
"requires": {
"discontinuous-range": "1.0.0",
"ret": "~0.1.10"
},
"dependencies": {
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
}
}
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -35710,11 +35540,11 @@
"integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w=="
},
"selderee": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.6.0.tgz",
"integrity": "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==",
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
"requires": {
"parseley": "^0.7.0"
"parseley": "^0.12.0"
}
},
"semver": {

View File

@@ -1,6 +1,6 @@
{
"name": "@notesnook/mobile",
"version": "2.4.12",
"version": "2.4.13",
"private": true,
"license": "GPL-3.0-or-later",
"workspaces": [

View File

@@ -1,59 +0,0 @@
diff --git a/node_modules/html-to-text/lib/formatter.js b/node_modules/html-to-text/lib/formatter.js
index d6cb1e6..68d0337 100644
--- a/node_modules/html-to-text/lib/formatter.js
+++ b/node_modules/html-to-text/lib/formatter.js
@@ -1,4 +1,4 @@
-const he = require('he');
+const {decode} = require('entities');
const { get, numberToLetterSequence, numberToRoman, splitClassesAndIds, trimCharacter } = require('./helper');
@@ -146,7 +146,7 @@ function withBrackets (str, brackets) {
function formatImage (elem, walk, builder, formatOptions) {
const attribs = elem.attribs || {};
const alt = (attribs.alt)
- ? he.decode(attribs.alt, builder.options.decodeOptions)
+ ? decode(attribs.alt, builder.options.decodeOptions)
: '';
const src = (!attribs.src)
? ''
@@ -176,7 +176,7 @@ function formatAnchor (elem, walk, builder, formatOptions) {
href = (formatOptions.baseUrl && href[0] === '/')
? formatOptions.baseUrl + href
: href;
- return he.decode(href, builder.options.decodeOptions);
+ return decode(href, builder.options.decodeOptions);
}
const href = getHref();
if (!href) {
diff --git a/node_modules/html-to-text/lib/html-to-text.js b/node_modules/html-to-text/lib/html-to-text.js
index 9ebda73..8c5345f 100644
--- a/node_modules/html-to-text/lib/html-to-text.js
+++ b/node_modules/html-to-text/lib/html-to-text.js
@@ -1,6 +1,6 @@
const { hp2Builder } = require('@selderee/plugin-htmlparser2');
const merge = require('deepmerge');
-const he = require('he');
+const {decode, EntityLevel} = require("entities");
const htmlparser = require('htmlparser2');
const selderee = require('selderee');
@@ -27,8 +27,7 @@ const DEFAULT_OPTIONS = {
returnDomByDefault: true
},
decodeOptions: {
- isAttributeValue: false,
- strict: false
+ level:EntityLevel.HTML
},
formatters: {},
limits: {
@@ -377,7 +376,7 @@ function recursiveWalk (walk, dom, builder) {
for (const elem of dom) {
switch (elem.type) {
case 'text': {
- builder.addInline(he.decode(elem.data, options.decodeOptions));
+ builder.addInline(decode(elem.data, options.decodeOptions));
break;
}
case 'tag': {

View File

@@ -0,0 +1,89 @@
diff --git a/node_modules/leac/lib/leac.cjs b/node_modules/leac/lib/leac.cjs
index 13123da..9d490e2 100644
--- a/node_modules/leac/lib/leac.cjs
+++ b/node_modules/leac/lib/leac.cjs
@@ -1 +1,83 @@
-"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=/\n/g;function t(t){const o=[...t.matchAll(e)].map((e=>e.index||0));o.unshift(-1);const s=n(o,0,o.length);return e=>r(s,e)}function n(e,t,r){if(r-t==1)return{offset:e[t],index:t+1};const o=Math.ceil((t+r)/2),s=n(e,t,o),l=n(e,o,r);return{offset:s.offset,low:s,high:l}}function r(e,t){return function(e){return Object.prototype.hasOwnProperty.call(e,"index")}(e)?{line:e.index,column:t-e.offset}:r(e.high.offset<t?e.high:e.low,t)}function o(e,t){return{...e,regex:s(e,t)}}function s(e,t){if(0===e.name.length)throw new Error(`Rule #${t} has empty name, which is not allowed.`);if(function(e){return Object.prototype.hasOwnProperty.call(e,"regex")}(e))return function(e){if(e.global)throw new Error(`Regular expression /${e.source}/${e.flags} contains the global flag, which is not allowed.`);return e.sticky?e:new RegExp(e.source,e.flags+"y")}(e.regex);if(function(e){return Object.prototype.hasOwnProperty.call(e,"str")}(e)){if(0===e.str.length)throw new Error(`Rule #${t} ("${e.name}") has empty "str" property, which is not allowed.`);return new RegExp(l(e.str),"y")}return new RegExp(l(e.name),"y")}function l(e){return e.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g,"\\$&")}exports.createLexer=function(e,n="",r={}){const s="string"!=typeof n?n:r,l="string"==typeof n?n:"",c=e.map(o),i=!!s.lineNumbers;return function(e,n=0){const r=i?t(e):()=>({line:0,column:0});let o=n;const s=[];e:for(;o<e.length;){let t=!1;for(const n of c){n.regex.lastIndex=o;const c=n.regex.exec(e);if(c&&c[0].length>0){if(!n.discard){const e=r(o),t="string"==typeof n.replace?c[0].replace(new RegExp(n.regex.source,n.regex.flags),n.replace):c[0];s.push({state:l,name:n.name,text:t,offset:o,len:c[0].length,line:e.line,column:e.column})}if(o=n.regex.lastIndex,t=!0,n.push){const t=n.push(e,o);s.push(...t.tokens),o=t.offset}if(n.pop)break e;break}}if(!t)break}return{tokens:s,offset:o,complete:e.length<=o}}};
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: !0 });
+const e = /\n/g;
+function t(t) {
+ const o = [...t.matchAll(e)].map((e) => e.index || 0);
+ o.unshift(-1);
+ const s = n(o, 0, o.length);
+ return (e) => r(s, e);
+}
+function n(e, t, r) {
+ if (r - t == 1) return { offset: e[t], index: t + 1 };
+ const o = Math.ceil((t + r) / 2),
+ s = n(e, t, o),
+ l = n(e, o, r);
+ return { offset: s.offset, low: s, high: l };
+}
+function r(e, t) {
+ return (function (e) {
+ return Object.prototype.hasOwnProperty.call(e, "index");
+ })(e)
+ ? { line: e.index, column: t - e.offset }
+ : r(e.high.offset < t ? e.high : e.low, t);
+}
+function _o(e, t) {
+ return { ...e, regex: s(e, t) };
+}
+function s(e, t) {
+ if (0 === e.name.length) throw new Error(`Rule #${t} has empty name, which is not allowed.`);
+ if (
+ (function (e) {
+ return Object.prototype.hasOwnProperty.call(e, "regex");
+ })(e)
+ )
+ return (function (e) {
+ if (e.global) throw new Error(`Regular expression /${e.source}/${e.flags} contains the global flag, which is not allowed.`);
+ return e.sticky ? e : new RegExp(e.source, e.flags + "y");
+ })(e.regex);
+ if (
+ (function (e) {
+ return Object.prototype.hasOwnProperty.call(e, "str");
+ })(e)
+ ) {
+ if (0 === e.str.length) throw new Error(`Rule #${t} ("${e.name}") has empty "str" property, which is not allowed.`);
+ return new RegExp(l(e.str), "y");
+ }
+ return new RegExp(l(e.name), "y");
+}
+function l(e) {
+ return e.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g, "\\$&");
+}
+exports.createLexer = function (_e, n = "", r = {}) {
+ const s = "string" != typeof n ? n : r,
+ l = "string" == typeof n ? n : "",
+ i = !!s.lineNumbers;
+ return function (e, n = 0) {
+ const r = i ? t(e) : () => ({ line: 0, column: 0 });
+ let o = n;
+ const s = [];
+ e: for (; o < e.length; ) {
+ let t = !1;
+ let z = _e.map(_o);
+ for (const n of z) {
+ n.regex.lastIndex = o;
+ const c = n.regex.exec(e);
+ if (c && c[0].length > 0) {
+ if (!n.discard) {
+ const e = r(o),
+ t = "string" == typeof n.replace ? c[0].replace(new RegExp(n.regex.source, n.regex.flags), n.replace) : c[0];
+ s.push({ state: l, name: n.name, text: t, offset: o, len: c[0].length, line: e.line, column: e.column });
+ }
+ if (((o = n.regex.lastIndex), (t = !0), n.push)) {
+ const t = n.push(e, o);
+ s.push(...t.tokens), (o = t.offset);
+ }
+ if (n.pop) break e;
+ break;
+ }
+ }
+ if (!t) break;
+ }
+ return { tokens: s, offset: o, complete: true };
+ };
+};

View File

@@ -26,12 +26,12 @@ import {
Keyboard,
Platform,
SafeAreaView,
ScrollView,
StatusBar,
Text,
TouchableOpacity,
useWindowDimensions,
View,
ScrollView
useWindowDimensions
} from "react-native";
import {
SafeAreaProvider,
@@ -45,10 +45,9 @@ import Storage from "../app/common/database/storage";
import { eSendEvent } from "../app/services/event-manager";
import { getElevation } from "../app/utils";
import { eOnLoadNote } from "../app/utils/events";
import { sleep } from "../app/utils/time";
import { Editor } from "./editor";
import { Search } from "./search";
import { initDatabase, useShareStore } from "./store";
import { Editor } from "./editor";
const getLinkPreview = (url) => {
return getPreviewData(url, 5000);
};
@@ -315,7 +314,6 @@ const ShareView = ({ quicknote = false }) => {
const onPress = async () => {
setLoading(true);
await initDatabase();
await sleep(1500);
if (!noteContent.current) return;
if (appendNote && !db.notes.note(appendNote.id)) {
useShareStore.getState().setAppendNote(null);
@@ -358,6 +356,7 @@ const ShareView = ({ quicknote = false }) => {
}
}
}
await db.sync(false, false);
await Storage.write("notesAddedFromIntent", "added");
close();
setLoading(false);

View File

@@ -29,10 +29,9 @@ import { db } from "../app/common/database";
export async function initDatabase() {
if (!db.isInitialized) {
// Only load collections in database.
await db.initCollections();
await db.notes.init();
await db.init();
}
await db.notes.init();
}
const StorageKeys = {

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/desktop",
"version": "2.4.7",
"version": "2.4.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/desktop",
"version": "2.4.7",
"version": "2.4.8",
"dependencies": {
"diary": "^0.3.1",
"electron-updater": "^5.3.0",

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "2.4.7",
"version": "2.4.8",
"appAppleId": "1544027013",
"private": true,
"main": "./build/electron.js",

View File

@@ -1,12 +1,12 @@
{
"name": "@notesnook/web",
"version": "2.4.7",
"version": "2.4.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@notesnook/web",
"version": "2.4.7",
"version": "2.4.8",
"license": "GPL-3.0-or-later",
"dependencies": {
"@aws-sdk/util-base64-browser": "^3.208.0",

View File

@@ -1,7 +1,7 @@
{
"name": "@notesnook/web",
"description": "Your private note taking space",
"version": "2.4.7",
"version": "2.4.8",
"private": true,
"main": "./src/app.js",
"homepage": "https://notesnook.com/",

View File

@@ -138,11 +138,6 @@
overflow: hidden;
}
* {
font-family: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
}
@keyframes fadeUp {
0% {
transform: translateY(500px);

View File

@@ -90,7 +90,13 @@ const features: Record<FeatureKeys, Feature> = {
}
]
: isDesktop()
? []
? [
{
title: "Default font size & font family",
subtitle:
"You can now change the default font family and size used by the editor across all your older & newer notes. Go into Settings > Editor settings to change these settings."
}
]
: [],
cta: {
title: "Got it",

View File

@@ -21,14 +21,19 @@ import { Button, Flex } from "@theme-ui/components";
import { useMenuTrigger } from "../../hooks/use-menu";
import { ChevronDown } from "../icons";
export default function DropdownButton({ title, options }) {
export default function DropdownButton(props) {
const { openMenu } = useMenuTrigger();
const { options, title, sx, buttonStyle, chevronStyle } = props;
if (!options || !options.length) return null;
return (
<Flex>
<Flex sx={sx}>
<Button
sx={{ borderTopRightRadius: 0, borderBottomRightRadius: 0 }}
sx={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
...buttonStyle
}}
onClick={options[0].onClick}
>
{options[0].title()}
@@ -38,7 +43,8 @@ export default function DropdownButton({ title, options }) {
px={1}
sx={{
borderBottomLeftRadius: 0,
borderTopLeftRadius: 0
borderTopLeftRadius: 0,
...chevronStyle
}}
onClick={() => openMenu(options.slice(1), { title })}
>

View File

@@ -24,17 +24,26 @@ import BaseStore from "../../stores";
import { UseBoundStore } from "zustand";
import shallow from "zustand/shallow";
import type { ToolbarDefinition } from "@notesnook/editor";
import Config from "../../utils/config";
type EditorConfig = { fontFamily: string; fontSize: number };
type EditorSubState = {
editor?: IEditor;
canUndo?: boolean;
canRedo?: boolean;
searching?: boolean;
toolbarConfig?: ToolbarDefinition;
editorConfig: EditorConfig;
statistics?: NoteStatistics;
};
class EditorContext extends BaseStore {
subState: EditorSubState = {};
subState: EditorSubState = {
editorConfig: Config.get("editorConfig", {
fontFamily: "sans-serif",
fontSize: 16
})
};
configure = (
partial:
@@ -116,3 +125,27 @@ export function useNoteStatistics(): NoteStatistics {
}
);
}
export function useEditorConfig() {
const editorConfig = useEditorContext((store) => store.subState.editorConfig);
const configure = useEditorContext((store) => store.configure);
const setEditorConfig = useCallback(
(config: Partial<EditorConfig>) => {
if (editorConfig)
Config.set("editorConfig", {
...editorConfig,
...config
});
configure({
editorConfig: {
...editorConfig,
...config
}
});
},
[editorConfig, configure]
);
return { editorConfig, setEditorConfig };
}

View File

@@ -33,9 +33,10 @@ import {
usePermissionHandler,
getHTMLFromFragment,
Fragment,
type DownloadOptions,
getTotalWords,
countWords,
type DownloadOptions
getFontById
} from "@notesnook/editor";
import { Box, Flex } from "@theme-ui/components";
import { PropsWithChildren, useEffect, useRef, useState } from "react";
@@ -45,7 +46,8 @@ import {
useConfigureEditor,
useSearch,
useToolbarConfig,
configureEditor
configureEditor,
useEditorConfig
} from "./context";
import { createPortal } from "react-dom";
import { getCurrentPreset } from "../../common/toolbar-config";
@@ -71,6 +73,8 @@ type TipTapProps = {
theme: Theme;
isMobile?: boolean;
downloadOptions?: DownloadOptions;
fontSize: number;
fontFamily: string;
};
const SAVE_INTERVAL = process.env.REACT_APP_TEST ? 100 : 300;
@@ -115,7 +119,9 @@ function TipTap(props: TipTapProps) {
nonce,
theme,
isMobile,
downloadOptions
downloadOptions,
fontSize,
fontFamily
} = props;
const isUserPremium = useIsUserPremium();
@@ -301,7 +307,6 @@ function TipTap(props: TipTapProps) {
}, [editor, editorContainer]);
if (!toolbarContainerId) return null;
return (
<>
<Portal containerId={toolbarContainerId}>
@@ -310,16 +315,24 @@ function TipTap(props: TipTapProps) {
theme={theme}
location={isMobile ? "bottom" : "top"}
tools={toolbarConfig}
defaultFontFamily={fontFamily}
defaultFontSize={fontSize}
/>
</Portal>
</>
);
}
function TiptapWrapper(props: Omit<TipTapProps, "editorContainer" | "theme">) {
function TiptapWrapper(
props: Omit<
TipTapProps,
"editorContainer" | "theme" | "fontSize" | "fontFamily"
>
) {
const theme = useTheme() as Theme;
const [isReady, setIsReady] = useState(false);
const editorContainerRef = useRef<HTMLDivElement>(null);
const { editorConfig } = useEditorConfig();
useEffect(() => {
setIsReady(true);
}, []);
@@ -332,6 +345,8 @@ function TiptapWrapper(props: Omit<TipTapProps, "editorContainer" | "theme">) {
{...props}
editorContainer={editorContainerRef.current}
theme={theme}
fontFamily={editorConfig.fontFamily}
fontSize={editorConfig.fontSize}
/>
) : null}
<Box
@@ -341,7 +356,9 @@ function TiptapWrapper(props: Omit<TipTapProps, "editorContainer" | "theme">) {
flex: 1,
cursor: "text",
color: theme.colors.text, // TODO!
paddingBottom: 150
paddingBottom: 150,
fontSize: editorConfig.fontSize,
fontFamily: getFontById(editorConfig.fontFamily)?.font
}}
/>
</Flex>

View File

@@ -23,6 +23,8 @@ import { useStore, store } from "../../stores/editor-store";
import { debounceWithId } from "../../utils/debounce";
import useMobile from "../../hooks/use-mobile";
import useTablet from "../../hooks/use-tablet";
import { useEditorConfig } from "./context";
import { getFontById } from "@notesnook/editor";
type TitleBoxProps = {
readonly: boolean;
@@ -35,6 +37,7 @@ function TitleBox(props: TitleBoxProps) {
const id = useStore((store) => store.session.id);
const isMobile = useMobile();
const isTablet = useTablet();
const { editorConfig } = useEditorConfig();
const MAX_FONT_SIZE = useMemo(() => {
return isMobile || isTablet ? 1.625 : 2.625;
@@ -66,7 +69,7 @@ function TitleBox(props: TitleBoxProps) {
readOnly={readonly}
sx={{
p: 0,
fontFamily: "heading",
fontFamily: getFontById(editorConfig.fontFamily)?.font || "heading",
fontSize: ["1.625em", "1.625em", "2.625em"],
fontWeight: "heading",
width: "100%"

View File

@@ -92,6 +92,7 @@ function Field(props) {
sx={{
fontSize: "subtitle",
fontWeight: "bold",
fontFamily: "body",
color: "icon",
flexDirection: "column",
...styles.label

View File

@@ -1019,13 +1019,14 @@ function openURL(url: string, force?: boolean) {
function maskEmail(email: string) {
if (!email) return "";
const [username, domain] = email.split("@");
const maskChars = "*".repeat(
username.substring(2, username.length - 2).length
);
return `${username.substring(0, 2)}${maskChars}${username.substring(
username.length - 2
)}@${domain}`;
const [username, provider] = email.split("@");
if (username.length === 1) return `****@${provider}`;
return email.replace(/(.{1})(.*)(?=@)/, function (gp1, gp2, gp3) {
for (let i = 0; i < gp3.length; i++) {
gp2 += "*";
}
return gp2;
});
}
function isSessionExpired() {

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useEffect, useMemo, useState } from "react";
import { Button, Flex, Text } from "@theme-ui/components";
import { Button, Flex, Input, Text } from "@theme-ui/components";
import * as Icon from "../components/icons";
import { useStore as useUserStore } from "../stores/user-store";
import { useStore as useNoteStore } from "../stores/note-store";
@@ -81,6 +81,8 @@ import { useTelemetry } from "../hooks/use-telemetry";
import useSpellChecker from "../hooks/use-spell-checker";
import useDesktopIntegration from "../hooks/use-desktop-integration";
import { writeText } from "clipboard-polyfill";
import { useEditorConfig } from "../components/editor/context";
import { getFonts } from "@notesnook/editor";
function subscriptionStatusToString(user) {
const status = user?.subscription?.type;
@@ -219,6 +221,7 @@ function Settings() {
"corsProxy",
"https://cors.notesnook.com"
);
const { editorConfig, setEditorConfig } = useEditorConfig();
useEffect(() => {
(async () => {
@@ -622,6 +625,51 @@ function Settings() {
/>
{groups.editor && (
<>
<OptionsItem
title={"Default font family"}
tip={"Set default font family"}
selectedOption={editorConfig.fontFamily}
options={getFonts().map((font) => ({
value: font.id,
title: font.title
}))}
onSelectionChanged={(option) => {
setEditorConfig({ fontFamily: option.value });
}}
/>
<Flex
py={2}
sx={{
cursor: "pointer",
borderBottom: "1px solid",
borderBottomColor: "border",
":hover": { borderBottomColor: "primary" },
alignItems: "center"
}}
>
<Tip
text="Default font size"
tip="Set default font size"
sx={{ flex: 1 }}
/>
<Input
type="number"
min={8}
sx={{ width: 70 }}
defaultValue={editorConfig.fontSize}
onChange={(e) => {
setEditorConfig({ fontSize: e.currentTarget.valueAsNumber });
}}
/>
</Flex>
{/* <Counter
value={editorConfig.fontSize}
onDecrease={() => {}}
onIncrease={() => {}}
title="Set default font size"
onReset={() => setEditorConfig({ fontFamily: "16px" })}
/> */}
{/* <DefaultFont /> */}
<Toggle
title="Use double spaced lines"
onTip="New lines will be double spaced (old ones won't be affected)."

View File

@@ -29,13 +29,13 @@ export default class Subscriptions {
}
async cancel() {
const token = this._tokenManager.getAccessToken();
const token = await this._tokenManager.getAccessToken();
if (!token) return;
await http.delete(`${hosts.SUBSCRIPTIONS_HOST}/subscriptions`, token);
}
async updateUrl() {
const token = this._tokenManager.getAccessToken();
const token = await this._tokenManager.getAccessToken();
if (!token) return;
return await http.get(
`${hosts.SUBSCRIPTIONS_HOST}/subscriptions/update_url`,

View File

@@ -50,7 +50,8 @@ export class Tiptap {
preserveNewlines: true,
selectors: [
{ selector: "table", format: "dataTable" },
{ selector: "ul.checklist", format: "taskList" }
{ selector: "ul.checklist", format: "taskList" },
{ selector: "p", format: "paragraph" }
],
formatters: {
taskList: (elem, walk, builder, formatOptions) => {

View File

@@ -24,6 +24,7 @@ import { getContentFromData } from "../content-types";
import { CHECK_IDS, checkIsUserPremium } from "../common";
import { addItem, deleteItem } from "../utils/array";
import { formatDate } from "../utils/date";
import qclone from "qclone";
export default class Note {
/**
@@ -135,12 +136,14 @@ export default class Note {
async duplicate() {
const content = await this._db.content.raw(this._note.contentId);
return await this._db.notes.add({
...this._note,
...qclone(this._note),
id: undefined,
content: {
type: content.type,
data: content.data
},
content: content
? {
type: content.type,
data: content.data
}
: undefined,
readonly: false,
favorite: false,
pinned: false,

View File

@@ -15261,8 +15261,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
"dev": true,
"requires": {}
"dev": true
},
"jest-regex-util": {
"version": "28.0.2",
@@ -15936,8 +15935,7 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"dev": true,
"requires": {}
"dev": true
}
}
},
@@ -17197,8 +17195,7 @@
"ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"requires": {}
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="
},
"xml-name-validator": {
"version": "4.0.0",

View File

@@ -33,16 +33,6 @@
color: var(--nn_placeholder) !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: "Open Sans";
color: var(--nn_heading);
}
#root {
height: 100%;
display: flex;

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import {
Editor,
getFontById,
PortalProvider,
Toolbar,
usePermissionHandler,
@@ -227,6 +228,7 @@ const Tiptap = ({
readonly={settings.readonly}
controller={controllerRef}
title={controller.title}
fontFamily={settings.fontFamily}
/>
<StatusBar container={containerRef} />
</>
@@ -234,6 +236,8 @@ const Tiptap = ({
<ContentDiv
padding={settings.doubleSpacedLines ? 0 : 6}
fontSize={settings.fontSize}
fontFamily={settings.fontFamily}
ref={contentRef}
/>
@@ -254,6 +258,8 @@ const Tiptap = ({
editor={_editor}
location="bottom"
tools={[...settings.tools]}
defaultFontFamily={settings.fontFamily}
defaultFontSize={settings.fontSize}
/>
)}
</div>
@@ -262,7 +268,10 @@ const Tiptap = ({
};
const ContentDiv = memo(
forwardRef<HTMLDivElement, { padding: number }>((props, ref) => {
forwardRef<
HTMLDivElement,
{ padding: number; fontSize: number; fontFamily: string }
>((props, ref) => {
const theme = useEditorThemeStore((state) => state.colors);
return (
<div
@@ -272,12 +281,18 @@ const ContentDiv = memo(
paddingTop: props.padding,
color: theme.pri,
marginTop: -12,
caretColor: theme.accent
caretColor: theme.accent,
fontSize: props.fontSize,
fontFamily: getFontById(props.fontFamily)?.font
}}
/>
);
}),
() => true
(prev, next) => {
if (prev.fontSize !== next.fontSize || prev.fontFamily !== next.fontFamily)
return false;
return true;
}
);
const modifyToolbarTheme = (toolbarTheme: Theme) => {

View File

@@ -17,20 +17,22 @@ 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 React from "react";
import { RefObject, useEffect, useRef } from "react";
import { getFontById } from "@notesnook/editor";
import React, { RefObject, useEffect, useRef } from "react";
import { EditorController } from "../hooks/useEditorController";
import styles from "./styles.module.css";
function Title({
controller,
title,
titlePlaceholder,
readonly
readonly,
fontFamily
}: {
controller: RefObject<EditorController>;
title: string;
titlePlaceholder: string;
readonly: boolean;
fontFamily: string;
}) {
const titleRef = useRef<HTMLInputElement>(null);
const emitUpdate = useRef(true);
@@ -59,7 +61,7 @@ function Title({
paddingRight: 12,
paddingLeft: 12,
fontWeight: 600,
fontFamily: "Open Sans",
fontFamily: getFontById(fontFamily)?.font || "Open Sans",
backgroundColor: "transparent",
color: "var(--nn_heading)",
caretColor: "var(--nn_accent)",
@@ -76,8 +78,13 @@ function Title({
}
export default React.memo(Title, (prev, next) => {
if (prev.title !== next.title) return false;
if (prev.titlePlaceholder !== next.titlePlaceholder) return false;
if (prev.readonly !== next.readonly) return false;
if (
prev.title !== next.title ||
prev.titlePlaceholder !== next.titlePlaceholder ||
prev.readonly !== next.readonly ||
prev.fontFamily !== next.fontFamily
)
return false;
return true;
});

View File

@@ -65,6 +65,7 @@ export type EditorController = {
titlePlaceholder: string;
openLink: (url: string) => boolean;
setTitlePlaceholder: React.Dispatch<React.SetStateAction<string>>;
countWords: (ms: number) => void;
};
export function useEditorController(update: () => void): EditorController {
@@ -84,21 +85,34 @@ export function useEditorController(update: () => void): EditorController {
post(EventTypes.title, title);
}, []);
const contentChange = useCallback((editor: Editor) => {
const currentSessionId = globalThis.sessionId;
post(EventTypes.contentchange);
if (!editor) return;
if (typeof timers.current.change === "number") {
clearTimeout(timers.current?.change);
}
timers.current.change = setTimeout(() => {
htmlContentRef.current = editor.getHTML();
post(EventTypes.content, htmlContentRef.current, currentSessionId);
}, 300);
countWords(5000);
const countWords = useCallback((ms = 300) => {
if (typeof timers.current.wordCounter === "number")
clearTimeout(timers.current.wordCounter);
timers.current.wordCounter = setTimeout(() => {
console.time("wordCounter");
statusBar?.current?.updateWords();
console.timeEnd("wordCounter");
}, ms);
}, []);
const contentChange = useCallback(
(editor: Editor) => {
const currentSessionId = globalThis.sessionId;
post(EventTypes.contentchange);
if (!editor) return;
if (typeof timers.current.change === "number") {
clearTimeout(timers.current?.change);
}
timers.current.change = setTimeout(() => {
htmlContentRef.current = editor.getHTML();
post(EventTypes.content, htmlContentRef.current, currentSessionId);
}, 300);
countWords(5000);
},
[countWords]
);
const scroll = useCallback(
(_event: React.UIEvent<HTMLDivElement, UIEvent>) => {},
[]
@@ -152,19 +166,9 @@ export function useEditorController(update: () => void): EditorController {
}
post(type); // Notify that message was delivered successfully.
},
[update]
[update, countWords]
);
function countWords(ms = 300) {
if (typeof timers.current.wordCounter === "number")
clearTimeout(timers.current.wordCounter);
timers.current.wordCounter = setTimeout(() => {
console.time("wordCounter");
statusBar?.current?.updateWords();
console.timeEnd("wordCounter");
}, ms);
}
useEffect(() => {
if (!isReactNative()) return; // Subscribe only in react native webview.
const isSafari = navigator.vendor.match(/apple/i);
@@ -208,6 +212,7 @@ export function useEditorController(update: () => void): EditorController {
previewAttachment,
content: htmlContentRef,
openLink,
onUpdate: onUpdate
onUpdate: onUpdate,
countWords
};
}

View File

@@ -30,7 +30,9 @@ const initialState = {
noToolbar: globalThis.noToolbar,
noHeader: globalThis.noHeader,
readonly: globalThis.readonly,
doubleSpacedLines: true
doubleSpacedLines: true,
fontFamily: "sans-serif",
fontSize: "16px"
};
global.settingsController = {

View File

@@ -39,6 +39,8 @@ export type Settings = {
noHeader?: boolean;
doubleSpacedLines?: boolean;
corsProxy: string;
fontSize: number;
fontFamily: string;
};
/* eslint-disable no-var */

View File

@@ -17,8 +17,8 @@ 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 "@tiptap/extension-text-style";
import { getFontConfig } from "@notesnook/theme/dist/theme/font";
import { Extension } from "@tiptap/core";
import { getFontById } from "../../utils/font";
export type FontFamilyOptions = {
types: string[];
@@ -39,12 +39,6 @@ declare module "@tiptap/core" {
}
}
const FONTS: Record<string, string> = {
monospace: getFontConfig().fonts.monospace,
"sans-serif": getFontConfig().fonts.body,
serif: `Noto Serif, Times New Roman, serif`
};
export const FontFamily = Extension.create<FontFamilyOptions>({
name: "fontFamily",
@@ -70,7 +64,8 @@ export const FontFamily = Extension.create<FontFamilyOptions>({
const realFontFamily =
attributes["data-font-family"] || attributes.fontFamily;
const font = FONTS[realFontFamily] || attributes.fontFamily;
const font =
getFontById(realFontFamily)?.font || attributes.fontFamily;
return {
"data-font-family": realFontFamily,
style: `font-family: ${font}`

View File

@@ -22,7 +22,6 @@ import "@tiptap/extension-text-style";
type FontSizeOptions = {
types: string[];
defaultFontSize: number;
};
declare module "@tiptap/core" {
@@ -44,8 +43,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
name: "fontSize",
defaultOptions: {
types: ["textStyle"],
defaultFontSize: 16
types: ["textStyle"]
},
addGlobalAttributes() {
@@ -54,7 +52,6 @@ export const FontSize = Extension.create<FontSizeOptions>({
types: this.options.types,
attributes: {
fontSize: {
default: `${this.options.defaultFontSize}px`,
parseHTML: (element) => element.style.fontSize,
renderHTML: (attributes) => {
if (!attributes.fontSize) {

View File

@@ -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 { Flex, Text } from "@theme-ui/components";
import { Box, Flex } from "@theme-ui/components";
import { ReactNodeViewProps } from "../react";
import { Icon } from "../../toolbar/components/icon";
import { Icons } from "../../toolbar/icons";
@@ -89,10 +89,10 @@ export function TaskItemComponent(
".icon:hover path": {
fill: "var(--checked) !important"
},
mt: "1px",
mx: 1
mx: 1,
fontFamily: "inherit"
}}
size={isMobile ? 24 : 20}
size={isMobile ? "2.46ch" : "2.22ch"}
/>
)}
<Icon
@@ -106,7 +106,6 @@ export function TaskItemComponent(
borderRadius: "default",
alignSelf: "start",
p: "1px",
mt: "2px",
mr: 1,
cursor: editor.isEditable ? "pointer" : "unset",
":hover": {
@@ -114,7 +113,8 @@ export function TaskItemComponent(
},
":hover .icon path": {
fill: "var(--checked) !important"
}
},
fontFamily: "inherit"
}}
onMouseDown={(e) => {
if (globalThis["keyboardShown"]) {
@@ -129,11 +129,10 @@ export function TaskItemComponent(
}
}}
color={checked ? "checked" : "icon"}
size={isMobile ? 16 : 14}
size={isMobile ? "1.66ch" : "1.46ch"}
/>
<Text
as="div"
<Box
ref={forwardRef}
sx={{
"> .taskitem-content-wrapper > p": {

View File

@@ -76,7 +76,7 @@ export function TaskListComponent(
sx={{
position: "relative",
bg: "bgSecondary",
py: 1,
py: "5px",
borderRadius: "default",
mb: 2,
alignItems: "center",
@@ -108,7 +108,8 @@ export function TaskListComponent(
px: 2,
zIndex: 1,
color: "fontTertiary",
fontSize: "title"
fontSize: "inherit",
fontFamily: "inherit"
}}
placeholder="Untitled"
onChange={(e) => {
@@ -168,15 +169,15 @@ export function TaskListComponent(
mr: 2,
color: "fontTertiary",
flexShrink: 0,
zIndex: 1
zIndex: 1,
fontFamily: "inherit"
}}
>
{stats.checked}/{stats.total}
</Text>
</Flex>
)}
<Text
as={"div"}
<Box
ref={forwardRef}
dir={textDirection}
sx={{

View File

@@ -273,6 +273,7 @@ export * from "./extensions/react";
export * from "./toolbar";
export * from "./types";
export * from "./utils/word-counter";
export * from "./utils/font";
export {
useTiptap,
Toolbar,

View File

@@ -64,6 +64,7 @@ export function Dropdown(props: DropdownProps) {
m: 0,
bg: isPopupOpen ? "hover" : "transparent",
mr: 1,
flexShrink: 0,
display: "flex",
alignItems: "center",
":hover": { bg: "hover" },
@@ -75,7 +76,9 @@ export function Dropdown(props: DropdownProps) {
onMouseDown={(e) => e.preventDefault()}
>
{typeof selectedItem === "string" ? (
<Text sx={{ fontSize: "subBody", mr: 1, color: "text" }}>
<Text
sx={{ fontSize: "subBody", mr: 1, color: "text", flexShrink: 0 }}
>
{selectedItem}
</Text>
) : (

View File

@@ -34,7 +34,7 @@ function isSchemeColor(
type IconProps = {
title?: string;
path: string;
size?: keyof Theme["iconSizes"] | number;
size?: keyof Theme["iconSizes"] | number | string;
color?: keyof SchemeColors | string;
stroke?: string;
rotate?: boolean;
@@ -60,8 +60,10 @@ function MDIIconWrapper({
title={title}
path={path}
size={
typeof size === "string"
? `${theme?.iconSizes[size] || 24}px`
theme && typeof size === "string" && size in theme.iconSizes
? `${(theme?.iconSizes as any)[size] || 24}px`
: typeof size === "string"
? size
: `${size}px`
}
style={{

View File

@@ -39,7 +39,8 @@ function _SplitButton(props: PropsWithChildren<SplitButtonProps>) {
<Flex
ref={ref}
sx={{
borderRadius: "default"
borderRadius: "default",
flexShrink: 0
}}
>
<ToolButton

View File

@@ -39,6 +39,10 @@ interface ToolbarState {
closePopup: (popupId: string) => void;
closePopupGroup: (groupId: string, excluded: string[]) => void;
closeAllPopups: () => void;
fontFamily: string;
setFontFamily: (fontFamily: string) => void;
fontSize: number;
setFontSize: (fontSize: number) => void;
}
export const useToolbarStore = create<ToolbarState>((set, get) => ({
@@ -92,6 +96,16 @@ export const useToolbarStore = create<ToolbarState>((set, get) => ({
for (const key in state.openedPopups) {
state.openedPopups[key] = undefined;
}
}),
fontFamily: "sans-serif",
setFontFamily: (fontFamily) =>
set((state) => {
state.fontFamily = fontFamily;
}),
fontSize: 16,
setFontSize: (fontSize) =>
set((state) => {
state.fontSize = fontSize;
})
}));

View File

@@ -41,6 +41,8 @@ type ToolbarProps = FlexProps & {
editor: Editor | null;
location: ToolbarLocation;
tools?: ToolbarDefinition;
defaultFontFamily: string;
defaultFontSize: number;
};
export function Toolbar(props: ToolbarProps) {
@@ -49,10 +51,11 @@ export function Toolbar(props: ToolbarProps) {
theme,
location,
tools = getDefaultPresets().default,
defaultFontFamily,
defaultFontSize,
sx,
...flexProps
} = props;
const toolbarTools = useMemo(
() => [...STATIC_TOOLBAR_GROUPS, ...tools],
[tools]
@@ -63,11 +66,23 @@ export function Toolbar(props: ToolbarProps) {
const setToolbarLocation = useToolbarStore(
(store) => store.setToolbarLocation
);
const setDefaultFontFamily = useToolbarStore((store) => store.setFontFamily);
const setDefaultFontSize = useToolbarStore((store) => store.setFontSize);
useEffect(() => {
setToolbarLocation(location);
}, [location, setToolbarLocation]);
useEffect(() => {
setDefaultFontFamily(defaultFontFamily);
setDefaultFontSize(defaultFontSize);
}, [
defaultFontFamily,
defaultFontSize,
setDefaultFontFamily,
setDefaultFontSize
]);
if (!editor) return null;
return (
<ThemeProvider theme={theme}>

View File

@@ -24,12 +24,16 @@ import { MenuItem } from "../../components/menu/types";
import { useCallback, useMemo } from "react";
import { Counter } from "../components/counter";
import { useRefValue } from "../../hooks/use-ref-value";
import { useToolbarStore } from "../stores/toolbar-store";
import { getFontById, getFontIds, getFonts } from "../../utils/font";
export function FontSize(props: ToolProps) {
const { editor } = props;
const { fontSize: _fontSize } = editor.getAttributes("textStyle");
const fontSize = _fontSize || "16px";
const fontSizeAsNumber = useRefValue(parseInt(fontSize.replace("px", "")));
const defaultFontSize = useToolbarStore((store) => store.fontSize);
const { fontSize } = editor.getAttributes("textStyle");
const fontSizeAsNumber = useRefValue(
fontSize ? parseInt(fontSize.replace("px", "")) : defaultFontSize
);
const decreaseFontSize = useCallback(() => {
return Math.max(8, fontSizeAsNumber.current - 1);
@@ -56,27 +60,26 @@ export function FontSize(props: ToolProps) {
.setFontSize(`${increaseFontSize()}px`)
.run();
}}
onReset={() => editor.current?.chain().focus().setFontSize("16px").run()}
value={fontSize}
onReset={() =>
editor.current
?.chain()
.focus()
.setFontSize(`${defaultFontSize}px`)
.run()
}
value={fontSize || `${defaultFontSize}px`}
/>
);
}
const fontFamilies = {
"Sans-serif": "Open Sans",
Serif: "serif",
Monospace: "monospace"
};
export function FontFamily(props: ToolProps) {
const { editor } = props;
const defaultFontFamily = useToolbarStore((store) => store.fontFamily);
const currentFontFamily =
Object.entries(fontFamilies)
.find(([_key, value]) =>
editor.isActive("textStyle", { fontFamily: value })
)
?.map((a) => a)
?.at(0) || "Sans-serif";
getFontIds().find((id) =>
editor.isActive("textStyle", { fontFamily: id })
) || defaultFontFamily;
const items = useMemo(
() => toMenuItems(editor, currentFontFamily),
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -87,7 +90,7 @@ export function FontFamily(props: ToolProps) {
<Dropdown
id="fontFamily"
group="font"
selectedItem={currentFontFamily}
selectedItem={getFontById(currentFontFamily)?.title || defaultFontFamily}
items={items}
menuWidth={130}
/>
@@ -96,16 +99,16 @@ export function FontFamily(props: ToolProps) {
function toMenuItems(editor: Editor, currentFontFamily: string): MenuItem[] {
const menuItems: MenuItem[] = [];
for (const key in fontFamilies) {
const value = fontFamilies[key as keyof typeof fontFamilies];
for (const font of getFonts()) {
menuItems.push({
key,
key: font.id,
type: "button",
title: key,
isChecked: key === currentFontFamily,
onClick: () => editor.current?.chain().focus().setFontFamily(value).run(),
title: font.title,
isChecked: font.id === currentFontFamily,
onClick: () =>
editor.current?.chain().focus().setFontFamily(font.id).run(),
styles: {
fontFamily: value
fontFamily: font.font
}
});
}

View File

@@ -17,15 +17,34 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function withAnimation(_duration = 300) {
return;
import { getFontConfig } from "@notesnook/theme/dist/theme/font";
const FONTS = [
{
title: "Monospace",
id: "monospace",
font: getFontConfig().fonts.monospace
},
{
title: "Sans-serif",
id: "sans-serif",
font: getFontConfig().fonts.body
},
{
title: "Serif",
id: "serif",
font: `Noto Serif, Times New Roman, serif`
}
];
export function getFonts() {
return FONTS;
}
function withSpringAnimation(_duration = 300) {
return;
export function getFontById(id: string) {
return FONTS.find((a) => a.id === id);
}
export default {
withAnimation,
withSpringAnimation
};
export function getFontIds() {
return FONTS.map((a) => a.id);
}

View File

@@ -1,7 +1,13 @@
.ProseMirror span * {
font-family: inherit;
}
.ProseMirror {
font-family: inherit;
}
.ProseMirror p.is-editor-empty:first-child::before {
color: var(--placeholder);
content: attr(data-placeholder);
@@ -87,6 +93,7 @@
.ProseMirror p {
margin-bottom: 0px;
font-family: inherit;
}
.ProseMirror > p[data-spacing="double"] {
@@ -502,7 +509,7 @@ p > *::selection {
.outline-list li > p::before {
position: absolute;
top: 4px;
top: 15%;
cursor: pointer;
content: "";
background-size: 18px;