mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 11:08:47 +02:00
Compare commits
42 Commits
2.4.14-and
...
2.4.17-and
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e221882f8e | ||
|
|
153ee4bce3 | ||
|
|
a2ecdab61c | ||
|
|
eb089e6211 | ||
|
|
1981c3a2f8 | ||
|
|
68b3ebe318 | ||
|
|
8a0b6264d2 | ||
|
|
239174c3e7 | ||
|
|
db1503d828 | ||
|
|
7b1cbba9e7 | ||
|
|
2c3c193629 | ||
|
|
899e56e9cd | ||
|
|
9c9582ae12 | ||
|
|
b918667b63 | ||
|
|
878c901e06 | ||
|
|
fdd3897a60 | ||
|
|
c958657b01 | ||
|
|
e7175f48a0 | ||
|
|
4e1862d653 | ||
|
|
1d5ac37222 | ||
|
|
32d027fff6 | ||
|
|
9434993373 | ||
|
|
2bd0f1a304 | ||
|
|
7f873f240e | ||
|
|
a0229729b7 | ||
|
|
dd368a4170 | ||
|
|
6d3e985c9d | ||
|
|
15858db21b | ||
|
|
b69a94a96f | ||
|
|
73b965eb7c | ||
|
|
5738f48360 | ||
|
|
de74b8c2cd | ||
|
|
2d07d79057 | ||
|
|
5f6a38c8b1 | ||
|
|
3496e6bfa9 | ||
|
|
fc5b62ba61 | ||
|
|
9d0a206240 | ||
|
|
ee6bbca18c | ||
|
|
e6d5472514 | ||
|
|
1e5f13087b | ||
|
|
abb89ecbc3 | ||
|
|
aa168bec5e |
@@ -31,14 +31,6 @@ import { TipManager } from "./services/tip-manager";
|
||||
import { useUserStore } from "./stores/use-user-store";
|
||||
import { View } from "react-native";
|
||||
import { useState } from "react";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
NetInfo.configure({
|
||||
reachabilityUrl: "https://notesnook.com",
|
||||
reachabilityTest: (response) => {
|
||||
if (!response) return false;
|
||||
return response?.status >= 200 && response?.status < 300;
|
||||
}
|
||||
});
|
||||
|
||||
SettingsService.init();
|
||||
SettingsService.checkOrientation();
|
||||
|
||||
@@ -22,7 +22,6 @@ import { TouchableOpacity, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../common/database";
|
||||
import { useAttachmentProgress } from "../../hooks/use-attachment-progress";
|
||||
import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { formatBytes } from "../../utils";
|
||||
import { SIZE } from "../../utils/size";
|
||||
@@ -47,9 +46,7 @@ export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
|
||||
attachment,
|
||||
encryption
|
||||
);
|
||||
const encryptionProgress = useAttachmentStore(
|
||||
(state) => state.encryptionProgress
|
||||
);
|
||||
|
||||
const onPress = () => {
|
||||
Actions.present(attachment, setAttachments, attachment.metadata.hash);
|
||||
};
|
||||
@@ -125,9 +122,7 @@ export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{currentProgress ||
|
||||
(encryptionProgress && encryptionProgress !== "0.00") ||
|
||||
encryption ? (
|
||||
{currentProgress ? (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.9}
|
||||
onPress={() => {
|
||||
@@ -144,13 +139,7 @@ export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
|
||||
>
|
||||
<ProgressCircleComponent
|
||||
size={SIZE.xxl}
|
||||
progress={
|
||||
encryptionProgress
|
||||
? encryptionProgress
|
||||
: currentProgress?.value
|
||||
? currentProgress?.value / 100
|
||||
: 0
|
||||
}
|
||||
progress={currentProgress?.value ? currentProgress?.value / 100 : 0}
|
||||
showsText
|
||||
textStyle={{
|
||||
fontSize: 10
|
||||
|
||||
@@ -70,6 +70,7 @@ const Launcher = React.memo(
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
const verifying = useRef(false);
|
||||
|
||||
const loadNotes = useCallback(async () => {
|
||||
if (verifyUser) {
|
||||
@@ -206,6 +207,9 @@ const Launcher = React.memo(
|
||||
setVerifyUser(false);
|
||||
enabled(false);
|
||||
password.current = null;
|
||||
setTimeout(() => {
|
||||
verifying.current = false;
|
||||
}, 1);
|
||||
}
|
||||
}, [setVerifyUser]);
|
||||
|
||||
@@ -214,7 +218,9 @@ const Launcher = React.memo(
|
||||
}, [init, verifyUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (verifying.current) return;
|
||||
if (verifyUser && appState === "active") {
|
||||
verifying.current = true;
|
||||
onUnlockBiometrics();
|
||||
}
|
||||
}, [appState, onUnlockBiometrics, verifyUser]);
|
||||
|
||||
@@ -17,10 +17,10 @@ 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, { useEffect, useRef, useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Animated, { FadeInUp, FadeOutUp } from "react-native-reanimated";
|
||||
import { editorState } from "../../screens/editor/tiptap/utils";
|
||||
import useKeyboard from "../../hooks/use-keyboard";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSendEvent,
|
||||
@@ -31,6 +31,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { getElevation } from "../../utils";
|
||||
import {
|
||||
eCloseActionSheet,
|
||||
eCloseSheet,
|
||||
eOpenPremiumDialog,
|
||||
eShowGetPremium
|
||||
} from "../../utils/events";
|
||||
@@ -39,12 +40,12 @@ import { sleep } from "../../utils/time";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [msg, setMsg] = useState(null);
|
||||
const timer = useRef();
|
||||
const keyboard = useKeyboard();
|
||||
|
||||
const open = useCallback(
|
||||
(event) => {
|
||||
@@ -72,7 +73,6 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eShowGetPremium, open);
|
||||
return () => {
|
||||
clearTimeout(timer.current);
|
||||
eUnSubscribeEvent(eShowGetPremium, open);
|
||||
};
|
||||
}, [open]);
|
||||
@@ -80,9 +80,7 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
const onPress = async () => {
|
||||
open(null);
|
||||
eSendEvent(eCloseActionSheet);
|
||||
if (editorState().isFocused) {
|
||||
//tiny.call(EditorWebView, tiny.blur);
|
||||
}
|
||||
eSendEvent(eCloseSheet);
|
||||
await sleep(300);
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
};
|
||||
@@ -102,9 +100,13 @@ export const PremiumToast = ({ context = "global", offset = 0 }) => {
|
||||
flexDirection: "row",
|
||||
alignSelf: "center",
|
||||
justifyContent: "space-between",
|
||||
top: offset,
|
||||
top: offset + keyboard.keyboardHeight,
|
||||
maxWidth: DDS.isLargeTablet() ? 400 : "98%"
|
||||
}}
|
||||
onTouchEnd={() => {
|
||||
setMsg(null);
|
||||
clearTimeout(timer.current);
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
|
||||
@@ -42,6 +42,7 @@ import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { eSendEvent } from "../../../services/event-manager";
|
||||
import { eCloseSheet } from "../../../utils/events";
|
||||
import { requestInAppReview } from "../../../services/app-review";
|
||||
|
||||
const ExportNotesSheet = ({ notes, update }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -72,6 +73,7 @@ const ExportNotesSheet = ({ notes, update }) => {
|
||||
update({ disableClosing: false });
|
||||
setComplete(true);
|
||||
setExporting(false);
|
||||
requestInAppReview();
|
||||
};
|
||||
|
||||
const actions = [
|
||||
|
||||
@@ -22,7 +22,7 @@ import { View } from "react-native";
|
||||
import { ScrollView } from "react-native-actions-sheet";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import { presentSheet, ToastEvent } from "../../../services/event-manager";
|
||||
import { ToastEvent, presentSheet } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { useTagStore } from "../../../stores/use-tag-store";
|
||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||
|
||||
@@ -35,6 +35,7 @@ import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { requestInAppReview } from "../../../services/app-review";
|
||||
|
||||
const PublishNoteSheet = ({ note: item, update }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -66,6 +67,7 @@ const PublishNoteSheet = ({ note: item, update }) => {
|
||||
Navigation.queueRoutesForUpdate();
|
||||
setPublishLoading(false);
|
||||
}
|
||||
requestInAppReview();
|
||||
} catch (e) {
|
||||
ToastEvent.show({
|
||||
heading: "Could not publish note",
|
||||
|
||||
@@ -520,7 +520,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
}
|
||||
|
||||
async function showAttachments() {
|
||||
AttachmentDialog.present();
|
||||
AttachmentDialog.present(item);
|
||||
}
|
||||
|
||||
async function exportNote() {
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAttachmentStore } from "../stores/use-attachment-store";
|
||||
|
||||
type AttachmentProgress = {
|
||||
@@ -41,22 +41,24 @@ export const useAttachmentProgress = (
|
||||
: undefined
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
useEffect(() => {
|
||||
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);
|
||||
}
|
||||
}, [attachment.metadata.hash, progress]);
|
||||
|
||||
return [currentProgress, setCurrentProgress];
|
||||
};
|
||||
|
||||
@@ -128,7 +128,6 @@ const Editor = React.memo(
|
||||
renderKey.current =
|
||||
renderKey.current === `editor-0` ? `editor-1` : `editor-0`;
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
}, [editor]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -167,6 +166,7 @@ const Editor = React.memo(
|
||||
injectedJavaScript={`globalThis.sessionId="${editor.sessionId}";`}
|
||||
javaScriptEnabled={true}
|
||||
focusable={true}
|
||||
onContentProcessDidTerminate={onError}
|
||||
setSupportMultipleWindows={false}
|
||||
overScrollMode="never"
|
||||
scrollEnabled={false}
|
||||
|
||||
@@ -101,8 +101,9 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
setTimeout(() => {
|
||||
if (!loadingState.current.startTime) {
|
||||
translateValue.value = 6000;
|
||||
opacity.value = 0;
|
||||
}
|
||||
}, 1000);
|
||||
}, 3000);
|
||||
eSubscribeEvent("loadingNote" + editorId, load);
|
||||
return () => {
|
||||
clearTimers();
|
||||
|
||||
@@ -80,8 +80,8 @@ export const useEditor = (
|
||||
const lockedSessionId = useRef<string>();
|
||||
|
||||
const postMessage = useCallback(
|
||||
async <T>(type: string, data: T) =>
|
||||
await post(editorRef, sessionIdRef.current, type, data),
|
||||
async <T>(type: string, data: T, waitFor = 300) =>
|
||||
await post(editorRef, sessionIdRef.current, type, data, waitFor),
|
||||
[sessionIdRef]
|
||||
);
|
||||
|
||||
@@ -120,9 +120,13 @@ export const useEditor = (
|
||||
[editorId]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
} else {
|
||||
state.current.ready = false;
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
const withTimer = useCallback(
|
||||
(id: string, fn: () => void, duration: number) => {
|
||||
@@ -336,7 +340,6 @@ export const useEditor = (
|
||||
) => {
|
||||
state.current.currentlyEditing = true;
|
||||
const editorState = useEditorStore.getState();
|
||||
|
||||
if (item && item.type === "new") {
|
||||
currentNote.current && (await reset());
|
||||
const nextSessionId = makeSessionId(item as NoteType);
|
||||
@@ -344,7 +347,7 @@ export const useEditor = (
|
||||
sessionIdRef.current = nextSessionId;
|
||||
sessionHistoryId.current = Date.now();
|
||||
await commands.setSessionId(nextSessionId);
|
||||
await commands.focus();
|
||||
if (state.current?.ready) await commands.focus();
|
||||
lastContentChangeTime.current = 0;
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
} else {
|
||||
@@ -358,7 +361,7 @@ export const useEditor = (
|
||||
!currentContent.current?.data ||
|
||||
currentContent.current?.data.length < 50000
|
||||
) {
|
||||
overlay(false);
|
||||
if (state.current.ready) overlay(false);
|
||||
} else {
|
||||
overlay(true);
|
||||
}
|
||||
@@ -372,7 +375,11 @@ export const useEditor = (
|
||||
currentNote.current = item as NoteType;
|
||||
await commands.setStatus(timeConverter(item.dateEdited), "Saved");
|
||||
await postMessage(EditorEvents.title, item.title);
|
||||
await postMessage(EditorEvents.html, currentContent.current?.data);
|
||||
await postMessage(
|
||||
EditorEvents.html,
|
||||
currentContent.current?.data,
|
||||
10000
|
||||
);
|
||||
useEditorStore.getState().setReadonly(item.readonly);
|
||||
await commands.setTags(currentNote.current);
|
||||
commands.setSettings();
|
||||
@@ -578,6 +585,10 @@ export const useEditor = (
|
||||
lastContentChangeTime.current = Date.now();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
state.current.saveCount = 0;
|
||||
}, [sessionId, loading]);
|
||||
|
||||
const onReady = useCallback(async () => {
|
||||
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
|
||||
eSendEvent("webview_reset");
|
||||
@@ -586,30 +597,24 @@ export const useEditor = (
|
||||
}
|
||||
}, [isDefaultEditor, restoreEditorState]);
|
||||
|
||||
useEffect(() => {
|
||||
state.current.saveCount = 0;
|
||||
(async () => {
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
if (sessionIdRef.current) {
|
||||
if (!state.current?.ready) return;
|
||||
await onReady();
|
||||
}
|
||||
})();
|
||||
}, [sessionId, loading, commands, onReady]);
|
||||
|
||||
const onLoad = useCallback(async () => {
|
||||
state.current.ready = true;
|
||||
onReady();
|
||||
postMessage(EditorEvents.theme, theme || useThemeStore.getState().colors);
|
||||
commands.setInsets(
|
||||
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
|
||||
);
|
||||
if (currentNote.current) {
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
}
|
||||
commands.setSettings();
|
||||
if (currentNote.current) overlay(true);
|
||||
clearTimeout(timers.current["editor:loaded"]);
|
||||
timers.current["editor:loaded"] = setTimeout(async () => {
|
||||
postMessage(EditorEvents.theme, theme || useThemeStore.getState().colors);
|
||||
commands.setInsets(
|
||||
isDefaultEditor ? insets : { top: 0, left: 0, right: 0, bottom: 0 }
|
||||
);
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
await onReady();
|
||||
await commands.setSettings();
|
||||
if (currentNote.current) {
|
||||
loadNote({ ...currentNote.current, forced: true });
|
||||
} else {
|
||||
await commands.setPlaceholder(placeholderTip.current);
|
||||
}
|
||||
state.current.ready = true;
|
||||
}, 300);
|
||||
}, [
|
||||
onReady,
|
||||
postMessage,
|
||||
@@ -617,7 +622,8 @@ export const useEditor = (
|
||||
commands,
|
||||
isDefaultEditor,
|
||||
insets,
|
||||
loadNote
|
||||
loadNote,
|
||||
overlay
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -73,7 +73,8 @@ export async function post<T>(
|
||||
ref: RefObject<WebView>,
|
||||
sessionId: string,
|
||||
type: string,
|
||||
value: T | null = null
|
||||
value: T | null = null,
|
||||
waitFor = 300
|
||||
) {
|
||||
if (!sessionId) {
|
||||
console.warn("post called without sessionId of type:", type);
|
||||
@@ -85,7 +86,7 @@ export async function post<T>(
|
||||
sessionId: sessionId
|
||||
};
|
||||
setImmediate(() => ref.current?.postMessage(JSON.stringify(message)));
|
||||
const response = await getResponse(type);
|
||||
const response = await getResponse(type, waitFor);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ type WebviewResponseData = {
|
||||
};
|
||||
|
||||
export const getResponse = async (
|
||||
type: string
|
||||
type: string,
|
||||
waitFor = 300
|
||||
): Promise<WebviewResponseData | false> => {
|
||||
return new Promise((resolve) => {
|
||||
const callback = (data: WebviewResponseData) => {
|
||||
@@ -107,7 +109,7 @@ export const getResponse = async (
|
||||
eSubscribeEvent(type, callback);
|
||||
setTimeout(() => {
|
||||
resolve(false);
|
||||
}, 5000);
|
||||
}, waitFor);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { getElevation } from "../../utils";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { requestInAppReview } from "../../services/app-review";
|
||||
const AppLock = ({ route }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const appLockMode = useSettingStore((state) => state.settings.appLockMode);
|
||||
@@ -151,6 +152,9 @@ const AppLock = ({ route }) => {
|
||||
return;
|
||||
}
|
||||
SettingsService.set({ appLockMode: item.value });
|
||||
if (!welcome) {
|
||||
requestInAppReview();
|
||||
}
|
||||
}}
|
||||
customStyle={{
|
||||
justifyContent: "flex-start",
|
||||
|
||||
44
apps/mobile/app/services/app-review.ts
Normal file
44
apps/mobile/app/services/app-review.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
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 InAppReview from "react-native-in-app-review";
|
||||
import { DatabaseLogger } from "../common/database";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
import Config from "react-native-config";
|
||||
|
||||
const day_ms = 86400000;
|
||||
export function requestInAppReview() {
|
||||
if (Config.GITHUB_RELEASE === "true") return;
|
||||
|
||||
const time = MMKV.getMap<{ timestamp: number }>("requestInAppReview");
|
||||
|
||||
if (time?.timestamp && time?.timestamp + day_ms * 7 > Date.now()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (InAppReview.isAvailable()) {
|
||||
InAppReview.RequestInAppReview()
|
||||
.then(() => {})
|
||||
.catch((error) => {
|
||||
DatabaseLogger.error(error);
|
||||
});
|
||||
MMKV.setMap("requestInAppReview", { timestamp: Date.now() });
|
||||
} else {
|
||||
DatabaseLogger.error(new Error("In App Review not available"));
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import { sleep } from "../utils/time";
|
||||
import { useRelationStore } from "../stores/use-relation-store";
|
||||
import { useReminderStore } from "../stores/use-reminder-store";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
|
||||
export type Reminder = {
|
||||
id: string;
|
||||
@@ -193,7 +194,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
case "Hide":
|
||||
unpinQuickNote();
|
||||
break;
|
||||
case "ReplyInput":
|
||||
case "ReplyInput": {
|
||||
displayNotification({
|
||||
title: "Quick note",
|
||||
message: 'Tap on "Take note" to add a note.',
|
||||
@@ -211,9 +212,17 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
data: `<p>${input} </p>`
|
||||
}
|
||||
});
|
||||
await db.sync(false, false);
|
||||
const status = await NetInfo.fetch();
|
||||
if (status.isInternetReachable) {
|
||||
try {
|
||||
await db.sync(false, false);
|
||||
} catch (e) {
|
||||
console.log(e, (e as Error).stack);
|
||||
}
|
||||
}
|
||||
useNoteStore.getState().setNotes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ async function getProducts() {
|
||||
}
|
||||
|
||||
function get() {
|
||||
if (__DEV__ || Config.isTesting) return true;
|
||||
if (__DEV__ || Config.isTesting === "true") return true;
|
||||
|
||||
return SUBSCRIPTION_STATUS.BASIC !== premiumStatus;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 2045
|
||||
versionCode 2048
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -51,8 +51,7 @@
|
||||
android:theme="@style/BootTheme"
|
||||
android:largeHeap="true"
|
||||
android:supportsRtl="false"
|
||||
tools:replace="android:supportsRtl"
|
||||
android:usesCleartextTraffic="true">
|
||||
tools:replace="android:supportsRtl">
|
||||
|
||||
<receiver android:exported="false" android:name=".NoteWidget">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
- Sync notes created from share extension & notification quick notes without requiring to launch the app
|
||||
- Fix formatting is lost when sharing notes to other apps
|
||||
- Fix editor would be blank after entering the app from background
|
||||
- Small bug fixes and ux improvements
|
||||
- Fix pro features locked accidentally for pro users
|
||||
- Added in app review
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -7,6 +7,15 @@ import Config from 'react-native-config';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import appJson from './app.json';
|
||||
import Notifications from "../app/services/notifications";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
NetInfo.configure({
|
||||
reachabilityUrl: "https://notesnook.com",
|
||||
reachabilityTest: (response) => {
|
||||
if (!response) return false;
|
||||
return response?.status >= 200 && response?.status < 300;
|
||||
}
|
||||
});
|
||||
|
||||
Notifications.init();
|
||||
|
||||
const appName = appJson.name;
|
||||
|
||||
@@ -993,7 +993,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1067,7 +1067,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
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 = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
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.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
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 = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
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.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
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 = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
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.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
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 = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
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.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
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 = 2037;
|
||||
CURRENT_PROJECT_VERSION = 2040;
|
||||
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.14;
|
||||
MARKETING_VERSION = 2.4.17;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -256,6 +256,8 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-image-resizer (3.0.5):
|
||||
- React-Core
|
||||
- react-native-in-app-review (4.3.3):
|
||||
- React-Core
|
||||
- react-native-keep-awake (1.1.0):
|
||||
- React-Core
|
||||
- react-native-mmkv-storage (0.8.0):
|
||||
@@ -460,6 +462,7 @@ DEPENDENCIES:
|
||||
- react-native-html-to-pdf-lite (from `../../node_modules/react-native-html-to-pdf-lite`)
|
||||
- react-native-image-picker (from `../../node_modules/react-native-image-picker`)
|
||||
- "react-native-image-resizer (from `../../node_modules/@bam.tech/react-native-image-resizer`)"
|
||||
- react-native-in-app-review (from `../../node_modules/react-native-in-app-review`)
|
||||
- "react-native-keep-awake (from `../../node_modules/@sayem314/react-native-keep-awake`)"
|
||||
- react-native-mmkv-storage (from `../../node_modules/react-native-mmkv-storage`)
|
||||
- "react-native-netinfo (from `../../node_modules/@react-native-community/netinfo`)"
|
||||
@@ -580,6 +583,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../../node_modules/react-native-image-picker"
|
||||
react-native-image-resizer:
|
||||
:path: "../../node_modules/@bam.tech/react-native-image-resizer"
|
||||
react-native-in-app-review:
|
||||
:path: "../../node_modules/react-native-in-app-review"
|
||||
react-native-keep-awake:
|
||||
:path: "../../node_modules/@sayem314/react-native-keep-awake"
|
||||
react-native-mmkv-storage:
|
||||
@@ -715,6 +720,7 @@ SPEC CHECKSUMS:
|
||||
react-native-html-to-pdf-lite: 21bfb169bf4cbcd7bec9f736975ee1b3f5292d4a
|
||||
react-native-image-picker: 9c8a2687b69300ad9e95cec5d38f35ab9d32467d
|
||||
react-native-image-resizer: 00ceb0e05586c7aadf061eea676957a6c2ec60fa
|
||||
react-native-in-app-review: db8bb167a5f238e7ceca5c242d6b36ce8c4404a4
|
||||
react-native-keep-awake: acbee258db16483744910f0da3ace39eb9ab47fd
|
||||
react-native-mmkv-storage: 8ba3c0216a6df283ece11205b442a3e435aec4e5
|
||||
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-actions-shortcuts": "^1.0.1"
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-in-app-review": "4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
|
||||
@@ -22,6 +22,11 @@ if (isGithubRelease) {
|
||||
android:null
|
||||
}
|
||||
}
|
||||
config.dependencies["react-native-in-app-review"] = {
|
||||
platforms: {
|
||||
android: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
- Sync notes created from share extension & notification quick notes in background
|
||||
- Fix formatting is lost when sharing notes to other apps
|
||||
- Fix editor would be blank after entering the app from background sometimes
|
||||
- Small bug fixes and UX improvements
|
||||
- Fix pro features locked accidentally for pro users
|
||||
- Added in app review
|
||||
|
||||
Thank you for using Notesnook!
|
||||
19
apps/mobile/package-lock.json
generated
19
apps/mobile/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.13",
|
||||
"version": "2.4.16",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.13",
|
||||
"version": "2.4.16",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
"native/",
|
||||
@@ -14,7 +14,8 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7"
|
||||
"react-native": "0.69.7",
|
||||
"react-native-in-app-review": "4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"otplib": "12.0.1",
|
||||
@@ -94,6 +95,7 @@
|
||||
"react-native-html-to-pdf-lite": "^0.9.1",
|
||||
"react-native-iap": "7.5.6",
|
||||
"react-native-image-picker": "4.1.2",
|
||||
"react-native-in-app-review": "4.3.3",
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-mmkv-storage": "^0.8.0",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
@@ -18292,6 +18294,11 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-in-app-review": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-in-app-review/-/react-native-in-app-review-4.3.3.tgz",
|
||||
"integrity": "sha512-Q9sXBtK8tCBYFPCGmMgeMlkxXC5e6vAyPZK26OC1oOKUuKUd0QORnryk/qbwnuN4fLshHQN8UKlLgyHLGRuK3A=="
|
||||
},
|
||||
"node_modules/react-native-keychain": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-4.0.5.tgz",
|
||||
@@ -24303,6 +24310,7 @@
|
||||
"react-native-html-to-pdf-lite": "^0.9.1",
|
||||
"react-native-iap": "7.5.6",
|
||||
"react-native-image-picker": "4.1.2",
|
||||
"react-native-in-app-review": "4.3.3",
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-mmkv-storage": "^0.8.0",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
@@ -34988,6 +34996,11 @@
|
||||
"react-native-image-pan-zoom": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"react-native-in-app-review": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-in-app-review/-/react-native-in-app-review-4.3.3.tgz",
|
||||
"integrity": "sha512-Q9sXBtK8tCBYFPCGmMgeMlkxXC5e6vAyPZK26OC1oOKUuKUd0QORnryk/qbwnuN4fLshHQN8UKlLgyHLGRuK3A=="
|
||||
},
|
||||
"react-native-keychain": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-4.0.5.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.14",
|
||||
"version": "2.4.17",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
|
||||
@@ -48,6 +48,7 @@ import { eOnLoadNote } from "../app/utils/events";
|
||||
import { Editor } from "./editor";
|
||||
import { Search } from "./search";
|
||||
import { initDatabase, useShareStore } from "./store";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
const getLinkPreview = (url) => {
|
||||
return getPreviewData(url, 5000);
|
||||
};
|
||||
@@ -355,7 +356,14 @@ const ShareView = ({ quicknote = false }) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
await db.sync(false, false);
|
||||
const status = await NetInfo.fetch();
|
||||
if (status.isInternetReachable) {
|
||||
try {
|
||||
await db.sync(false, false);
|
||||
} catch (e) {
|
||||
console.log(e, e.stack);
|
||||
}
|
||||
}
|
||||
await Storage.write("notesAddedFromIntent", "added");
|
||||
close();
|
||||
setLoading(false);
|
||||
|
||||
4
apps/web/desktop/package-lock.json
generated
4
apps/web/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"dependencies": {
|
||||
"diary": "^0.3.1",
|
||||
"electron-updater": "^5.3.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./build/electron.js",
|
||||
|
||||
@@ -23,6 +23,7 @@ import { createReadStream } from "fs";
|
||||
import { extname, normalize } from "path";
|
||||
import { logger } from "./logger";
|
||||
import { URL } from "url";
|
||||
import { Blob } from "buffer";
|
||||
|
||||
const FILE_NOT_FOUND = -6;
|
||||
const BASE_PATH = isDevelopment() ? "../public" : "";
|
||||
@@ -67,7 +68,31 @@ function registerProtocol() {
|
||||
mimeType: extensionToMimeType[fileExtension]
|
||||
});
|
||||
} else {
|
||||
protocol.uninterceptProtocol(PROTOCOL);
|
||||
var response;
|
||||
try {
|
||||
const body = await getBody(request);
|
||||
response = await fetch(request.url, {
|
||||
...request,
|
||||
body,
|
||||
headers: {
|
||||
...request.headers
|
||||
// origin: `${PROTOCOL}://${HOSTNAME}/`
|
||||
},
|
||||
referrer: request.referrer,
|
||||
redirect: "manual"
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
logger.error(`Error sending request to `, request.url, "Error: ", e);
|
||||
callback({ statusCode: 400 });
|
||||
return;
|
||||
}
|
||||
callback({
|
||||
statusCode: response.status,
|
||||
data: response.body,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
mimeType: response.headers.get("Content-Type")
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -85,5 +110,29 @@ function shouldInterceptRequest(url) {
|
||||
return shouldIntercept && !bypassedRoutes.includes(url.pathname);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Electron.ProtocolRequest} request
|
||||
*/
|
||||
async function getBody(request) {
|
||||
/**
|
||||
* @type {Electron.Session}
|
||||
*/
|
||||
const session = globalThis?.window?.webContents?.session;
|
||||
|
||||
const blobParts = [];
|
||||
if (!request.uploadData || !request.uploadData.length) return null;
|
||||
for (let data of request.uploadData) {
|
||||
if (data.type === "rawData") {
|
||||
blobParts.push(new Uint8Array(data.bytes));
|
||||
} else if (session && data.type === "blob") {
|
||||
const buffer = await session.getBlobData(data.blobUUID);
|
||||
blobParts.push(new Uint8Array(buffer));
|
||||
}
|
||||
}
|
||||
const blob = new Blob(blobParts);
|
||||
return await blob.arrayBuffer();
|
||||
}
|
||||
|
||||
const PROTOCOL_URL = `${PROTOCOL}://${HOSTNAME}/`;
|
||||
export { registerProtocol, PROTOCOL_URL };
|
||||
|
||||
4
apps/web/package-lock.json
generated
4
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@aws-sdk/util-base64-browser": "^3.208.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "2.4.9",
|
||||
"version": "2.4.11",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||
@@ -45,11 +45,8 @@ import { isTesting } from "./utils/platform";
|
||||
import { updateStatus, removeStatus, getStatus } from "./hooks/use-status";
|
||||
import { showToast } from "./utils/toast";
|
||||
import { interruptedOnboarding } from "./components/dialogs/onboarding-dialog";
|
||||
import { WebExtensionRelay } from "./utils/web-extension-relay";
|
||||
import { hashNavigate } from "./navigation";
|
||||
|
||||
const relay = new WebExtensionRelay();
|
||||
|
||||
export default function AppEffects({ setShow }) {
|
||||
const refreshNavItems = useStore((store) => store.refreshNavItems);
|
||||
const updateLastSynced = useStore((store) => store.updateLastSynced);
|
||||
@@ -103,7 +100,6 @@ export default function AppEffects({ setShow }) {
|
||||
await showOnboardingDialog(interruptedOnboarding());
|
||||
await showFeatureDialog("highlights");
|
||||
await scheduleBackups();
|
||||
relay.connect();
|
||||
})();
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -35,6 +35,9 @@ import StatusBar from "./components/status-bar";
|
||||
import { EditorLoader } from "./components/loaders/editor-loader";
|
||||
import { FlexScrollContainer } from "./components/scroll-container";
|
||||
import CachedRouter from "./components/cached-router";
|
||||
import { WebExtensionRelay } from "./utils/web-extension-relay";
|
||||
|
||||
new WebExtensionRelay();
|
||||
|
||||
const GlobalMenuWrapper = React.lazy(() =>
|
||||
import("./components/global-menu-wrapper")
|
||||
|
||||
@@ -211,8 +211,9 @@ export function showError(title: string, message: string) {
|
||||
export function showMultiDeleteConfirmation(length: number) {
|
||||
return confirm({
|
||||
title: `Delete ${length} items?`,
|
||||
message: `These items will be **kept in your Trash for ${db.settings?.getTrashCleanupInterval() || 7
|
||||
} days** after which they will be permanently deleted.`,
|
||||
message: `These items will be **kept in your Trash for ${
|
||||
db.settings?.getTrashCleanupInterval() || 7
|
||||
} days** after which they will be permanently deleted.`,
|
||||
positiveButtonText: "Yes",
|
||||
negativeButtonText: "No"
|
||||
});
|
||||
@@ -331,6 +332,12 @@ export function showMoveNoteDialog(noteIds: string[]) {
|
||||
));
|
||||
}
|
||||
|
||||
export function showBillingHistoryDialog() {
|
||||
return showDialog("BillingHistoryDialog", (Dialog, perform) => (
|
||||
<Dialog onClose={(res: boolean) => perform(res)} />
|
||||
));
|
||||
}
|
||||
|
||||
function getDialogData(type: string) {
|
||||
switch (type) {
|
||||
case "create_vault":
|
||||
|
||||
145
apps/web/src/components/dialogs/billing-history-dialog.tsx
Normal file
145
apps/web/src/components/dialogs/billing-history-dialog.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
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 { useEffect, useState } from "react";
|
||||
import { Perform } from "../../common/dialog-controller";
|
||||
import Dialog from "./dialog";
|
||||
import { db } from "../../common/db";
|
||||
import { Loading } from "../icons";
|
||||
import { Flex, Link, Text } from "@theme-ui/components";
|
||||
import { formatDate } from "@notesnook/core/utils/date";
|
||||
|
||||
type Transaction = {
|
||||
order_id: string;
|
||||
checkout_id: string;
|
||||
amount: string;
|
||||
currency: string;
|
||||
status: keyof typeof TransactionStatusToText;
|
||||
created_at: Date;
|
||||
passthrough: null;
|
||||
product_id: number;
|
||||
is_subscription: boolean;
|
||||
is_one_off: boolean;
|
||||
subscription: Subscription;
|
||||
user: User;
|
||||
receipt_url: string;
|
||||
};
|
||||
|
||||
type Subscription = {
|
||||
subscription_id: number;
|
||||
status: string;
|
||||
};
|
||||
|
||||
type User = {
|
||||
user_id: number;
|
||||
email: string;
|
||||
marketing_consent: boolean;
|
||||
};
|
||||
|
||||
const TransactionStatusToText = {
|
||||
completed: "Completed",
|
||||
refunded: "Refunded",
|
||||
partially_refunded: "Partially refunded",
|
||||
disputed: "Disputed"
|
||||
};
|
||||
|
||||
export type BillingHistoryDialogProps = {
|
||||
onClose: Perform;
|
||||
};
|
||||
|
||||
export default function BillingHistoryDialog(props: BillingHistoryDialogProps) {
|
||||
const [transactions, setTransactions] = useState<Transaction[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<Error | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
try {
|
||||
setError(undefined);
|
||||
setIsLoading(true);
|
||||
|
||||
const transactions = await db.subscriptions?.transactions();
|
||||
if (!transactions) return;
|
||||
setTransactions(transactions);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) setError(e);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={true}
|
||||
title={"Billing history"}
|
||||
description={"View all the transactions you have made with Notesnook."}
|
||||
onClose={() => props.onClose(false)}
|
||||
negativeButton={{ text: "Close", onClick: () => props.onClose(false) }}
|
||||
width={600}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loading sx={{ mt: 2 }} />
|
||||
) : error ? (
|
||||
<Flex sx={{ bg: "errorBg", p: 1, borderRadius: "default" }}>
|
||||
<Text variant="error">
|
||||
{error.message}
|
||||
<br />
|
||||
{error.stack}
|
||||
</Text>
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex sx={{ flexDirection: "column", gap: 1, mt: 1 }}>
|
||||
{transactions.map((transaction) => (
|
||||
<Flex
|
||||
key={transaction.order_id}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
borderBottom: "1px solid var(--border)",
|
||||
pb: 1
|
||||
}}
|
||||
>
|
||||
<Flex sx={{ flexDirection: "column" }}>
|
||||
<Text variant="subtitle">Order #{transaction.order_id}</Text>
|
||||
<Text variant="body" sx={{ color: "fontTertiary" }}>
|
||||
{formatDate(new Date(transaction.created_at).getTime())} •{" "}
|
||||
{TransactionStatusToText[transaction.status]}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex sx={{ flexDirection: "column", alignItems: "end" }}>
|
||||
<Text variant="body">
|
||||
{transaction.amount} {transaction.currency}
|
||||
</Text>
|
||||
<Link
|
||||
href={transaction.receipt_url}
|
||||
target="_blank"
|
||||
rel="noreferer nofollow"
|
||||
variant="text.subBody"
|
||||
sx={{ color: "primary" }}
|
||||
>
|
||||
View receipt
|
||||
</Link>
|
||||
</Flex>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -55,6 +55,8 @@ export function BuyDialog(props: BuyDialogProps) {
|
||||
const theme = useTheme() as Theme;
|
||||
|
||||
const onApplyCoupon = useCheckoutStore((store) => store.applyCoupon);
|
||||
const isCheckoutCompleted = useCheckoutStore((store) => store.isCompleted);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
useCheckoutStore.getState().reset();
|
||||
@@ -118,7 +120,7 @@ export function BuyDialog(props: BuyDialogProps) {
|
||||
boxShadow: "4px 5px 18px 2px #00000038",
|
||||
borderRadius: "dialog",
|
||||
flexDirection: ["column", "column", "row"],
|
||||
width: ["95%", "80%", "60%"],
|
||||
width: ["95%", "80%", isCheckoutCompleted ? "400px" : "60%"],
|
||||
maxHeight: ["95%", "80%", "80%"],
|
||||
alignSelf: "center",
|
||||
overflowY: ["scroll", "scroll", "hidden"]
|
||||
@@ -139,7 +141,7 @@ export function BuyDialog(props: BuyDialogProps) {
|
||||
flexShrink: 0,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: ["100%", "100%", 350]
|
||||
width: ["100%", "100%", isCheckoutCompleted ? "100%" : 350]
|
||||
}}
|
||||
p={4}
|
||||
py={50}
|
||||
@@ -165,6 +167,9 @@ function SideBar(props: SideBarProps) {
|
||||
const user = useUserStore((store) => store.user);
|
||||
const couponCode = useCheckoutStore((store) => store.couponCode);
|
||||
const onApplyCoupon = useCheckoutStore((store) => store.applyCoupon);
|
||||
const isCheckoutCompleted = useCheckoutStore((store) => store.isCompleted);
|
||||
|
||||
if (isCheckoutCompleted) return <CheckoutCompleted onClose={onClose} />;
|
||||
|
||||
if (user && selectedPlan)
|
||||
return (
|
||||
@@ -230,12 +235,16 @@ function Details() {
|
||||
const user = useUserStore((store) => store.user);
|
||||
const selectedPlan = useCheckoutStore((state) => state.selectedPlan);
|
||||
const onPriceUpdated = useCheckoutStore((state) => state.updatePrice);
|
||||
const completeCheckout = useCheckoutStore((state) => state.completeCheckout);
|
||||
const isCheckoutCompleted = useCheckoutStore((store) => store.isCompleted);
|
||||
const couponCode = useCheckoutStore((store) => store.couponCode);
|
||||
const setIsApplyingCoupon = useCheckoutStore(
|
||||
(store) => store.setIsApplyingCoupon
|
||||
);
|
||||
const theme = useThemeStore((store) => store.theme);
|
||||
|
||||
if (isCheckoutCompleted) return null;
|
||||
|
||||
if (selectedPlan && user)
|
||||
return (
|
||||
<PaddleCheckout
|
||||
@@ -243,6 +252,7 @@ function Details() {
|
||||
theme={theme}
|
||||
user={user}
|
||||
coupon={couponCode}
|
||||
onCompleted={completeCheckout}
|
||||
onCouponApplied={() => setIsApplyingCoupon(true)}
|
||||
onPriceUpdated={(pricingInfo) => {
|
||||
onPriceUpdated(pricingInfo);
|
||||
@@ -396,6 +406,31 @@ function AlreadyPremium(props: AlreadyPremiumProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function CheckoutCompleted(props: { onClose: () => void }) {
|
||||
const { onClose } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Rocket width={200} />
|
||||
<Text variant="heading" mt={4} sx={{ textAlign: "center" }}>
|
||||
Thank you!
|
||||
</Text>
|
||||
<Text variant="body" mt={1} sx={{ textAlign: "center" }}>
|
||||
You have successfully subscribed to Notesnook Pro.
|
||||
</Text>
|
||||
<Button
|
||||
variant="primary"
|
||||
mt={2}
|
||||
sx={{ borderRadius: 100, px: 6 }}
|
||||
onClick={onClose}
|
||||
data-test-id="see-all-plans"
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
type SelectedPlanProps = {
|
||||
plan: Plan;
|
||||
pricingInfo: PricingInfo | undefined;
|
||||
|
||||
@@ -33,13 +33,25 @@ import {
|
||||
|
||||
// const isDev = false; // process.env.NODE_ENV === "development";
|
||||
// const VENDOR_ID = isDev ? 1506 : 128190;
|
||||
const PADDLE_ORIGIN = "https://buy.paddle.com";
|
||||
const PADDLE_ORIGIN =
|
||||
process.env.NODE_ENV === "development"
|
||||
? "https://sandbox-buy.paddle.com"
|
||||
: "https://buy.paddle.com";
|
||||
const CHECKOUT_CREATE_ORIGIN =
|
||||
process.env.NODE_ENV === "development"
|
||||
? "https://sandbox-create-checkout.paddle.com"
|
||||
: "https://create-checkout.paddle.com";
|
||||
const CHECKOUT_SERVICE_ORIGIN =
|
||||
process.env.NODE_ENV === "development"
|
||||
? "https://sandbox-checkout-service.paddle.com"
|
||||
: "https://checkout-service.paddle.com";
|
||||
|
||||
const SUBSCRIBED_EVENTS: PaddleEvents[] = [
|
||||
PaddleEvents["Checkout.Loaded"],
|
||||
PaddleEvents["Checkout.Coupon.Applied"],
|
||||
PaddleEvents["Checkout.Coupon.Remove"],
|
||||
PaddleEvents["Checkout.Location.Submit"]
|
||||
PaddleEvents["Checkout.Location.Submit"],
|
||||
PaddleEvents["Checkout.Complete"]
|
||||
];
|
||||
|
||||
type PaddleCheckoutProps = {
|
||||
@@ -48,10 +60,11 @@ type PaddleCheckoutProps = {
|
||||
plan: Plan;
|
||||
onPriceUpdated?: (pricingInfo: PricingInfo) => void;
|
||||
onCouponApplied?: () => void;
|
||||
onCompleted?: () => void;
|
||||
coupon?: string;
|
||||
};
|
||||
export function PaddleCheckout(props: PaddleCheckoutProps) {
|
||||
const { plan, onPriceUpdated, coupon, onCouponApplied } = props;
|
||||
const { plan, onPriceUpdated, coupon, onCouponApplied, onCompleted } = props;
|
||||
const [sourceUrl, setSourceUrl] = useState<string>();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [checkoutId, setCheckoutId] = useState<string>();
|
||||
@@ -61,7 +74,7 @@ export function PaddleCheckout(props: PaddleCheckoutProps) {
|
||||
const reloadCheckout = useCallback(() => {
|
||||
if (!checkoutRef.current) return;
|
||||
setIsLoading(true);
|
||||
checkoutRef.current.src = `https://buy.paddle.com/checkout/?checkout_id=${checkoutId}&display_mode=inline&apple_pay_enabled=false`;
|
||||
checkoutRef.current.src = `${PADDLE_ORIGIN}/checkout/?checkout_id=${checkoutId}&display_mode=inline&apple_pay_enabled=false`;
|
||||
}, [checkoutId]);
|
||||
|
||||
const updatePrice = useCallback(
|
||||
@@ -96,6 +109,10 @@ export function PaddleCheckout(props: PaddleCheckoutProps) {
|
||||
)
|
||||
return;
|
||||
|
||||
if (event_name === PaddleEvents["Checkout.Complete"]) {
|
||||
onCompleted && onCompleted();
|
||||
return;
|
||||
}
|
||||
if (event_name === PaddleEvents["Checkout.Loaded"]) setIsLoading(false);
|
||||
|
||||
const pricingInfo = await updatePrice(checkout.id);
|
||||
@@ -108,7 +125,7 @@ export function PaddleCheckout(props: PaddleCheckoutProps) {
|
||||
return () => {
|
||||
window.removeEventListener("message", onMessage);
|
||||
};
|
||||
}, [onPriceUpdated, updatePrice, plan]);
|
||||
}, [onPriceUpdated, updatePrice, plan, onCompleted]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -173,7 +190,7 @@ export function PaddleCheckout(props: PaddleCheckoutProps) {
|
||||
|
||||
async function getCheckoutURL(params: PaddleCheckoutProps) {
|
||||
const { plan, theme, user } = params;
|
||||
const BASE_URL = `https://create-checkout.paddle.com/checkout/product/${plan.id}`;
|
||||
const BASE_URL = `${CHECKOUT_CREATE_ORIGIN}/checkout/product/${plan.id}`;
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.set("product", plan.id);
|
||||
queryParams.set("passthrough", JSON.stringify({ userId: user.id }));
|
||||
@@ -227,7 +244,7 @@ async function applyCoupon(
|
||||
checkoutId: string,
|
||||
couponCode: string
|
||||
): Promise<CheckoutData | false> {
|
||||
const url = ` https://checkout-service.paddle.com/checkout/${checkoutId}/coupon`;
|
||||
const url = ` ${CHECKOUT_SERVICE_ORIGIN}/checkout/${checkoutId}/coupon`;
|
||||
const body = { data: { coupon_code: couponCode } };
|
||||
const headers = new Headers();
|
||||
headers.set("content-type", "application/json");
|
||||
@@ -246,7 +263,7 @@ async function applyCoupon(
|
||||
}
|
||||
|
||||
async function removeCoupon(checkoutId: string): Promise<CheckoutData | false> {
|
||||
const url = ` https://checkout-service.paddle.com/checkout/${checkoutId}/coupon`;
|
||||
const url = ` ${CHECKOUT_SERVICE_ORIGIN}/checkout/${checkoutId}/coupon`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "DELETE"
|
||||
@@ -260,7 +277,7 @@ async function removeCoupon(checkoutId: string): Promise<CheckoutData | false> {
|
||||
}
|
||||
|
||||
async function sendCheckoutEvent(checkoutId: string, eventName: PaddleEvents) {
|
||||
const url = ` https://checkout-service.paddle.com/checkout/${checkoutId}/event`;
|
||||
const url = ` ${CHECKOUT_SERVICE_ORIGIN}/checkout/${checkoutId}/event`;
|
||||
const body = { data: { event_name: eventName } };
|
||||
const headers = new Headers();
|
||||
headers.set("content-type", "application/json");
|
||||
@@ -275,7 +292,7 @@ async function sendCheckoutEvent(checkoutId: string, eventName: PaddleEvents) {
|
||||
async function getCheckoutData(
|
||||
checkoutId: string
|
||||
): Promise<CheckoutData | undefined> {
|
||||
const url = `https://checkout-service.paddle.com/checkout/${checkoutId}`;
|
||||
const url = `${CHECKOUT_SERVICE_ORIGIN}/checkout/${checkoutId}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) return undefined;
|
||||
const json = (await response.json()) as CheckoutDataResponse;
|
||||
|
||||
@@ -32,7 +32,7 @@ export const DEFAULT_PLANS: Plan[] = [
|
||||
country: "PK",
|
||||
currency: "USD",
|
||||
discount: 0,
|
||||
id: "648884",
|
||||
id: process.env.NODE_ENV === "development" ? "9822" : "648884",
|
||||
price: { gross: 4.49, net: 0, tax: 0 }
|
||||
},
|
||||
{
|
||||
@@ -40,7 +40,7 @@ export const DEFAULT_PLANS: Plan[] = [
|
||||
country: "PK",
|
||||
currency: "USD",
|
||||
discount: 0,
|
||||
id: "658759",
|
||||
id: process.env.NODE_ENV === "development" ? "50305" : "658759",
|
||||
price: { gross: 49.99, net: 0, tax: 0 }
|
||||
}
|
||||
];
|
||||
@@ -52,7 +52,8 @@ export const PLAN_METADATA: Record<Period, PlanMetadata> = {
|
||||
|
||||
let CACHED_PLANS: Plan[];
|
||||
export async function getPlans(): Promise<Plan[] | null> {
|
||||
if (isTesting()) return DEFAULT_PLANS;
|
||||
if (isTesting() || process.env.NODE_ENV === "development")
|
||||
return DEFAULT_PLANS;
|
||||
if (CACHED_PLANS) return CACHED_PLANS;
|
||||
|
||||
const url = `https://notesnook.com/api/v1/prices/products/web`;
|
||||
|
||||
@@ -22,6 +22,8 @@ import create from "zustand";
|
||||
import produce from "immer";
|
||||
|
||||
interface ICheckoutStore {
|
||||
isCompleted: boolean;
|
||||
completeCheckout: () => void;
|
||||
selectedPlan?: Plan;
|
||||
selectPlan: (plan?: Plan) => void;
|
||||
pricingInfo?: PricingInfo;
|
||||
@@ -33,10 +35,17 @@ interface ICheckoutStore {
|
||||
reset: () => void;
|
||||
}
|
||||
export const useCheckoutStore = create<ICheckoutStore>((set) => ({
|
||||
isCompleted: false,
|
||||
selectedPlan: undefined,
|
||||
pricingInfo: undefined,
|
||||
couponCode: undefined,
|
||||
isApplyingCoupon: false,
|
||||
completeCheckout: () =>
|
||||
set(
|
||||
produce((state: ICheckoutStore) => {
|
||||
state.isCompleted = true;
|
||||
})
|
||||
),
|
||||
selectPlan: (plan) =>
|
||||
set(
|
||||
produce((state: ICheckoutStore) => {
|
||||
|
||||
@@ -22,7 +22,7 @@ import Dialog from "./dialog";
|
||||
import { getHomeRoute, hardNavigate } from "../../navigation";
|
||||
import { appVersion } from "../../utils/version";
|
||||
import Config from "../../utils/config";
|
||||
import { isDesktop, isTesting } from "../../utils/platform";
|
||||
import { isTesting } from "../../utils/platform";
|
||||
import { useEffect } from "react";
|
||||
import { ArrowRight, Checkmark, Icon, Warn } from "../icons";
|
||||
|
||||
@@ -89,9 +89,18 @@ const features: Record<FeatureKeys, Feature> = {
|
||||
)
|
||||
}
|
||||
]
|
||||
: isDesktop()
|
||||
? []
|
||||
: [],
|
||||
: [
|
||||
{
|
||||
title: "Billing history",
|
||||
subtitle:
|
||||
"You can now get a list of all the transactions you have made, their amount and when they were made."
|
||||
},
|
||||
{
|
||||
title: "Request refund",
|
||||
subtitle:
|
||||
"You can now request refunds directly from inside the app. No need for emails etc. Go to Settings > Request refund to send your request for a refund."
|
||||
}
|
||||
],
|
||||
cta: {
|
||||
title: "Got it",
|
||||
icon: Checkmark,
|
||||
|
||||
@@ -57,6 +57,9 @@ const EmailChangeDialog = React.lazy(() => import("./email-change-dialog"));
|
||||
const LanguageSelectorDialog = React.lazy(
|
||||
() => import("./language-selector-dialog")
|
||||
);
|
||||
const BillingHistoryDialog = React.lazy(
|
||||
() => import("./billing-history-dialog")
|
||||
);
|
||||
|
||||
export const Dialogs = {
|
||||
AddNotebookDialog,
|
||||
@@ -85,5 +88,6 @@ export const Dialogs = {
|
||||
AddReminderDialog,
|
||||
ReminderPreviewDialog,
|
||||
EmailChangeDialog,
|
||||
LanguageSelectorDialog
|
||||
LanguageSelectorDialog,
|
||||
BillingHistoryDialog
|
||||
};
|
||||
|
||||
@@ -200,6 +200,8 @@ function Autosuggest({
|
||||
if (e.key === "ArrowDown" && !text) onOpenMenu(defaultItems.slice());
|
||||
|
||||
e.preventDefault();
|
||||
} else if (e.key === "Tab") {
|
||||
closeMenu();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -156,6 +156,7 @@ class EditorStore extends BaseStore {
|
||||
}
|
||||
});
|
||||
appStore.setIsEditorOpen(true);
|
||||
this.toggleProperties(false);
|
||||
};
|
||||
|
||||
saveSession = async (sessionId, session) => {
|
||||
|
||||
@@ -35,7 +35,7 @@ function isDocumentHidden() {
|
||||
|
||||
export function onPageVisibilityChanged(
|
||||
handler: (
|
||||
status: "online" | "offline" | "visibilitychange",
|
||||
status: "online" | "offline" | "visibilitychange" | "focus",
|
||||
bool: boolean
|
||||
) => void
|
||||
) {
|
||||
@@ -46,6 +46,8 @@ export function onPageVisibilityChanged(
|
||||
document.addEventListener(visibilityChange(), () =>
|
||||
handler("visibilitychange", isDocumentHidden())
|
||||
);
|
||||
|
||||
window.addEventListener("focus", () => handler("focus", false));
|
||||
}
|
||||
|
||||
function onDeviceOnline(handler: () => void) {
|
||||
|
||||
@@ -19,22 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { expose, Remote, wrap } from "comlink";
|
||||
import { updateStatus } from "../hooks/use-status";
|
||||
import { db } from "../common/db";
|
||||
import {
|
||||
Gateway,
|
||||
ItemReference,
|
||||
NotebookReference,
|
||||
Server,
|
||||
Clip,
|
||||
WEB_EXTENSION_CHANNEL_EVENTS
|
||||
} from "@notesnook/web-clipper/dist/common/bridge";
|
||||
import { isUserPremium } from "../hooks/use-is-user-premium";
|
||||
import { store as themestore } from "../stores/theme-store";
|
||||
import { store as appstore } from "../stores/app-store";
|
||||
import { formatDate } from "@notesnook/core/utils/date";
|
||||
import { h } from "./html";
|
||||
import { sanitizeFilename } from "./filename";
|
||||
import { attachFile } from "../components/editor/picker";
|
||||
|
||||
export class WebExtensionRelay {
|
||||
private gateway?: Remote<Gateway>;
|
||||
@@ -52,6 +40,8 @@ export class WebExtensionRelay {
|
||||
|
||||
async connect(): Promise<boolean> {
|
||||
if (this.gateway) return true;
|
||||
const { WebExtensionServer } = await import("./web-extension-server");
|
||||
|
||||
const channel = new MessageChannel();
|
||||
channel.port1.start();
|
||||
channel.port2.start();
|
||||
@@ -76,96 +66,3 @@ export class WebExtensionRelay {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class WebExtensionServer implements Server {
|
||||
async login() {
|
||||
const user = await db.user?.getUser();
|
||||
if (!user) return null;
|
||||
const { theme, accent } = themestore.get();
|
||||
return { email: user.email, pro: isUserPremium(user), accent, theme };
|
||||
}
|
||||
|
||||
async getNotes(): Promise<ItemReference[] | undefined> {
|
||||
await db.notes?.init();
|
||||
|
||||
return db.notes?.all
|
||||
.filter((n) => !n.locked)
|
||||
.map((note) => ({ id: note.id, title: note.title }));
|
||||
}
|
||||
|
||||
async getNotebooks(): Promise<NotebookReference[] | undefined> {
|
||||
return db.notebooks?.all.map((nb) => ({
|
||||
id: nb.id,
|
||||
title: nb.title,
|
||||
topics: nb.topics.map((topic: ItemReference) => ({
|
||||
id: topic.id,
|
||||
title: topic.title
|
||||
}))
|
||||
}));
|
||||
}
|
||||
|
||||
async getTags(): Promise<ItemReference[] | undefined> {
|
||||
return db.tags?.all.map((tag) => ({
|
||||
id: tag.id,
|
||||
title: tag.title
|
||||
}));
|
||||
}
|
||||
|
||||
async saveClip(clip: Clip) {
|
||||
let clipContent = "";
|
||||
|
||||
if (clip.mode === "simplified" || clip.mode === "screenshot") {
|
||||
clipContent += clip.data;
|
||||
} else {
|
||||
const clippedFile = new File(
|
||||
[new TextEncoder().encode(clip.data).buffer],
|
||||
`${sanitizeFilename(clip.title)}.clip`,
|
||||
{
|
||||
type: "application/vnd.notesnook.web-clip"
|
||||
}
|
||||
);
|
||||
|
||||
const attachment = await attachFile(clippedFile);
|
||||
if (!attachment) return;
|
||||
|
||||
clipContent += h("iframe", [], {
|
||||
"data-hash": attachment.hash,
|
||||
"data-mime": attachment.type,
|
||||
src: clip.url,
|
||||
title: clip.pageTitle || clip.title,
|
||||
width: clip.width ? `${clip.width}` : undefined,
|
||||
height: clip.height ? `${clip.height}` : undefined,
|
||||
class: "web-clip"
|
||||
}).outerHTML;
|
||||
}
|
||||
|
||||
const note =
|
||||
(clip.note?.id && db.notes?.note(clip.note?.id)) ||
|
||||
db.notes?.note(await db.notes?.add({ title: clip.title }));
|
||||
let content = (await note?.content()) || "";
|
||||
content += clipContent;
|
||||
content += h("div", [
|
||||
h("hr"),
|
||||
h("p", ["Clipped from ", h("a", [clip.title], { href: clip.url })]),
|
||||
h("p", [`Date clipped: ${formatDate(Date.now())}`])
|
||||
]).innerHTML;
|
||||
|
||||
await db.notes?.add({
|
||||
id: note?.id,
|
||||
content: { type: "tiptap", data: content }
|
||||
});
|
||||
|
||||
if (clip.notebook && note) {
|
||||
await db.notes?.addToNotebook(
|
||||
{ id: clip.notebook.id, topic: clip.notebook.topic.id },
|
||||
note.id
|
||||
);
|
||||
}
|
||||
if (clip.tags && note) {
|
||||
for (const tag of clip.tags) {
|
||||
await db.tags?.add(tag, note.id);
|
||||
}
|
||||
}
|
||||
await appstore.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
131
apps/web/src/utils/web-extension-server.ts
Normal file
131
apps/web/src/utils/web-extension-server.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
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 { db } from "../common/db";
|
||||
import {
|
||||
ItemReference,
|
||||
NotebookReference,
|
||||
Server,
|
||||
Clip
|
||||
} from "@notesnook/web-clipper/dist/common/bridge";
|
||||
import { isUserPremium } from "../hooks/use-is-user-premium";
|
||||
import { store as themestore } from "../stores/theme-store";
|
||||
import { store as appstore } from "../stores/app-store";
|
||||
import { formatDate } from "@notesnook/core/utils/date";
|
||||
import { h } from "./html";
|
||||
import { sanitizeFilename } from "./filename";
|
||||
import { attachFile } from "../components/editor/picker";
|
||||
|
||||
export class WebExtensionServer implements Server {
|
||||
async login() {
|
||||
const user = await db.user?.getUser();
|
||||
const { theme, accent } = themestore.get();
|
||||
if (!user) return { pro: false, theme, accent };
|
||||
return { email: user.email, pro: isUserPremium(user), theme, accent };
|
||||
}
|
||||
|
||||
async getNotes(): Promise<ItemReference[] | undefined> {
|
||||
await db.notes?.init();
|
||||
|
||||
return db.notes?.all
|
||||
.filter((n) => !n.locked)
|
||||
.map((note) => ({ id: note.id, title: note.title }));
|
||||
}
|
||||
|
||||
async getNotebooks(): Promise<NotebookReference[] | undefined> {
|
||||
return db.notebooks?.all.map((nb) => ({
|
||||
id: nb.id,
|
||||
title: nb.title,
|
||||
topics: nb.topics.map((topic: ItemReference) => ({
|
||||
id: topic.id,
|
||||
title: topic.title
|
||||
}))
|
||||
}));
|
||||
}
|
||||
|
||||
async getTags(): Promise<ItemReference[] | undefined> {
|
||||
return db.tags?.all.map((tag) => ({
|
||||
id: tag.id,
|
||||
title: tag.title
|
||||
}));
|
||||
}
|
||||
|
||||
async saveClip(clip: Clip) {
|
||||
let clipContent = "";
|
||||
|
||||
if (clip.mode === "simplified" || clip.mode === "screenshot") {
|
||||
clipContent += clip.data;
|
||||
} else {
|
||||
const clippedFile = new File(
|
||||
[new TextEncoder().encode(clip.data).buffer],
|
||||
`${sanitizeFilename(clip.title)}.clip`,
|
||||
{
|
||||
type: "application/vnd.notesnook.web-clip"
|
||||
}
|
||||
);
|
||||
|
||||
const attachment = await attachFile(clippedFile);
|
||||
if (!attachment) return;
|
||||
|
||||
clipContent += h("iframe", [], {
|
||||
"data-hash": attachment.hash,
|
||||
"data-mime": attachment.type,
|
||||
src: clip.url,
|
||||
title: clip.pageTitle || clip.title,
|
||||
width: clip.width ? `${clip.width}` : undefined,
|
||||
height: clip.height ? `${clip.height}` : undefined,
|
||||
class: "web-clip"
|
||||
}).outerHTML;
|
||||
}
|
||||
|
||||
const note = clip.note?.id ? db.notes?.note(clip.note?.id) : null;
|
||||
|
||||
let content = (await note?.content()) || "";
|
||||
content += clipContent;
|
||||
content += h("div", [
|
||||
h("hr"),
|
||||
h("p", ["Clipped from ", h("a", [clip.title], { href: clip.url })]),
|
||||
h("p", [`Date clipped: ${formatDate(Date.now())}`])
|
||||
]).innerHTML;
|
||||
|
||||
const id = await db.notes?.add({
|
||||
id: note?.id,
|
||||
title: note ? note.title : clip.title,
|
||||
content: { type: "tiptap", data: content },
|
||||
tags: note ? note.tags : clip.tags
|
||||
});
|
||||
|
||||
if (clip.refs && id && !clip.note) {
|
||||
for (const ref of clip.refs) {
|
||||
switch (ref.type) {
|
||||
case "notebook":
|
||||
await db.notes?.addToNotebook({ id: ref.id }, id);
|
||||
break;
|
||||
case "topic":
|
||||
await db.notes?.addToNotebook(
|
||||
{ id: ref.parentId, topic: ref.id },
|
||||
id
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
await appstore.refresh();
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,8 @@ import {
|
||||
showPromptDialog,
|
||||
showEmailChangeDialog,
|
||||
showLanguageSelectorDialog,
|
||||
confirm
|
||||
confirm,
|
||||
showBillingHistoryDialog
|
||||
} from "../common/dialog-controller";
|
||||
import { TaskManager } from "../common/task-manager";
|
||||
import { SUBSCRIPTION_STATUS } from "../common/constants";
|
||||
@@ -1357,6 +1358,46 @@ function AccountStatus(props) {
|
||||
tip="Update the payment method you used to purchase this subscription."
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="list"
|
||||
onClick={async () => {
|
||||
const refundSubscription = await confirm({
|
||||
title: "Request refund?",
|
||||
message:
|
||||
"You will only be issued a refund if you are eligible as per our refund policy. Your account will be immediately downgraded to Basic and your funds will be transferred to your account within 24 hours.",
|
||||
negativeButtonText: "No",
|
||||
positiveButtonText: "Yes"
|
||||
});
|
||||
if (refundSubscription) {
|
||||
const error = await TaskManager.startTask({
|
||||
id: "refund-subscription",
|
||||
type: "modal",
|
||||
title: "Requesting refund for your subscription",
|
||||
subtitle: "Please wait...",
|
||||
action: () => db.subscriptions.refund()
|
||||
});
|
||||
if (error instanceof Error) {
|
||||
showToast("error", error.message);
|
||||
} else {
|
||||
showToast(
|
||||
"success",
|
||||
"Your refund has been issued. Please wait 24 hours before reaching out to us in case you do not receive your funds."
|
||||
);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Tip
|
||||
text="Request refund"
|
||||
tip="If you are eligible for a refund, your account will be immediately downgraded to Basic and your funds will be transferred to your account within 24 hours."
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="list" onClick={() => showBillingHistoryDialog()}>
|
||||
<Tip
|
||||
text="Billing history"
|
||||
tip="View all the transactions you have made with Notesnook."
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="list"
|
||||
sx={{ ":hover": { borderColor: "error" } }}
|
||||
@@ -1379,11 +1420,8 @@ function AccountStatus(props) {
|
||||
});
|
||||
showToast(
|
||||
"success",
|
||||
"Your subscription has been cancelled."
|
||||
"Your subscription has been canceled."
|
||||
);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 5000);
|
||||
}
|
||||
} catch (e) {
|
||||
showToast("error", e.message);
|
||||
|
||||
@@ -31,39 +31,30 @@ const ACTION = {
|
||||
default_popup: "popup.html"
|
||||
};
|
||||
|
||||
const nnHost =
|
||||
process.env.NODE_ENV === "production"
|
||||
? "*://app.notesnook.com/*"
|
||||
: "*://localhost/*";
|
||||
const corsHost = "https://cors.notesnook.com/*";
|
||||
const common = {
|
||||
name: "Notesnook Web Clipper",
|
||||
version: "0.1",
|
||||
description: "Clip web pages.",
|
||||
permissions: [
|
||||
"activeTab",
|
||||
"tabs",
|
||||
"storage",
|
||||
"contextMenus",
|
||||
"notifications",
|
||||
"<all_urls>"
|
||||
],
|
||||
content_scripts: [
|
||||
{
|
||||
js: ["nnContentScript.bundle.js"],
|
||||
matches: ["*://app.notesnook.com/*", "*://localhost/*"]
|
||||
},
|
||||
{
|
||||
js: ["contentScript.bundle.js"],
|
||||
matches: ["http://*/*", "https://*/*"],
|
||||
exclude_matches: ["*://app.notesnook.com/*", "*://localhost/*"]
|
||||
}
|
||||
],
|
||||
browser_specific_settings: {
|
||||
gecko: {
|
||||
strict_min_version: "105.0"
|
||||
}
|
||||
},
|
||||
version: "0.2.0",
|
||||
description:
|
||||
"Clip web pages & save interesting things you find on the web directly into Notesnook in a private & secure way.",
|
||||
permissions: ["activeTab", "tabs", "storage", "notifications"],
|
||||
icons: ICONS
|
||||
};
|
||||
|
||||
const v2 = {
|
||||
...common,
|
||||
permissions: [...common.permissions, corsHost, nnHost],
|
||||
optional_permissions: ["http://*/*", "https://*/*"],
|
||||
browser_specific_settings: {
|
||||
gecko: {
|
||||
id: "notesnook-web-clipper-unlisted@notesnook.com",
|
||||
strict_min_version: "105.0"
|
||||
}
|
||||
},
|
||||
manifest_version: 2,
|
||||
background: {
|
||||
scripts: [BACKGROUND_SCRIPT]
|
||||
@@ -73,6 +64,8 @@ const v2 = {
|
||||
|
||||
const v3 = {
|
||||
...common,
|
||||
host_permissions: [corsHost, nnHost],
|
||||
optional_host_permissions: ["http://*/*", "https://*/*"],
|
||||
manifest_version: 3,
|
||||
background: {
|
||||
service_worker: BACKGROUND_SCRIPT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/web-clipper",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -16,7 +16,7 @@ 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 { browser, Runtime } from "webextension-polyfill-ts";
|
||||
import { browser, Runtime, Tabs } from "webextension-polyfill-ts";
|
||||
import { Remote, wrap } from "comlink";
|
||||
import { createEndpoint } from "./utils/comlink-extension";
|
||||
import { Server } from "./common/bridge";
|
||||
@@ -28,19 +28,48 @@ let api: Remote<Server> | undefined;
|
||||
export async function connectApi(openNew = false, onDisconnect?: () => void) {
|
||||
if (api) return api;
|
||||
|
||||
const tab = await getTab(openNew);
|
||||
if (!tab) return false;
|
||||
const tabs = await findNotesnookTabs(openNew);
|
||||
for (const tab of tabs) {
|
||||
try {
|
||||
const api = await Promise.race([
|
||||
connectToTab(tab, onDisconnect),
|
||||
timeout(5000)
|
||||
]);
|
||||
if (!api) continue;
|
||||
return api as Remote<Server>;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
return await new Promise<Remote<Server> | false>(function connect(resolve) {
|
||||
if (!tab.id) return resolve(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const port = browser.tabs.connect(tab.id);
|
||||
function timeout(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms, false));
|
||||
}
|
||||
|
||||
port.onDisconnect.addListener(() => {
|
||||
api = undefined;
|
||||
onDisconnect?.();
|
||||
async function connectToTab(tab: Tabs.Tab, onDisconnect?: () => void) {
|
||||
if (!tab.id) return false;
|
||||
|
||||
if (browser.scripting) {
|
||||
await browser.scripting.executeScript({
|
||||
files: ["nnContentScript.bundle.js"],
|
||||
target: { tabId: tab.id }
|
||||
});
|
||||
} else {
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
file: "nnContentScript.bundle.js"
|
||||
});
|
||||
}
|
||||
|
||||
const port = browser.tabs.connect(tab.id);
|
||||
port.onDisconnect.addListener(() => {
|
||||
api = undefined;
|
||||
onDisconnect?.();
|
||||
});
|
||||
|
||||
return new Promise<Remote<Server> | false>(function connect(resolve) {
|
||||
async function onMessage(
|
||||
message: WebExtensionChannelMessage,
|
||||
port: Runtime.Port
|
||||
@@ -58,23 +87,26 @@ export async function connectApi(openNew = false, onDisconnect?: () => void) {
|
||||
});
|
||||
}
|
||||
|
||||
async function getTab(openNew = false) {
|
||||
export async function findNotesnookTabs(openNew = false) {
|
||||
const tabs = await browser.tabs.query({
|
||||
url: APP_URL_FILTER
|
||||
url: APP_URL_FILTER,
|
||||
discarded: false,
|
||||
status: "complete"
|
||||
});
|
||||
|
||||
if (tabs.length) return tabs[0];
|
||||
if (tabs.length) return tabs;
|
||||
|
||||
if (openNew) {
|
||||
const [tab] = await Promise.all([
|
||||
browser.tabs.create({ url: APP_URL, active: false }),
|
||||
new Promise((resolve) => {
|
||||
browser.runtime.onMessage.addListener((message) => {
|
||||
if (message.type === "start_connection") resolve(true);
|
||||
});
|
||||
const tab = await browser.tabs.create({ url: APP_URL, active: false });
|
||||
await new Promise<void>((resolve) =>
|
||||
browser.tabs.onUpdated.addListener(function onUpdated(id, info) {
|
||||
if (id === tab.id && info.status === "complete") {
|
||||
browser.tabs.onUpdated.removeListener(onUpdated);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
]);
|
||||
return tab;
|
||||
);
|
||||
return [tab];
|
||||
}
|
||||
return undefined;
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export type ClipArea = "full-page" | "visible" | "selection" | "article";
|
||||
export type ClipMode = "simplified" | "screenshot" | "complete";
|
||||
|
||||
export type User = {
|
||||
email: string;
|
||||
email?: string;
|
||||
pro: boolean;
|
||||
accent: string;
|
||||
theme: "dark" | "light";
|
||||
@@ -45,7 +45,18 @@ export interface Gateway {
|
||||
connect(): ClientMetadata;
|
||||
}
|
||||
|
||||
export type SelectedNotebook = ItemReference & { topic: ItemReference };
|
||||
type SelectedTopicReference = ItemReference & {
|
||||
type: "topic";
|
||||
parentId: string;
|
||||
};
|
||||
|
||||
type SelectedNotebookReference = ItemReference & {
|
||||
type: "notebook";
|
||||
};
|
||||
|
||||
export type SelectedReference =
|
||||
| SelectedTopicReference
|
||||
| SelectedNotebookReference;
|
||||
|
||||
export type Clip = {
|
||||
url: string;
|
||||
@@ -58,7 +69,7 @@ export type Clip = {
|
||||
pageTitle?: string;
|
||||
tags?: string[];
|
||||
note?: ItemReference;
|
||||
notebook?: SelectedNotebook;
|
||||
refs?: SelectedReference[];
|
||||
};
|
||||
|
||||
export interface Server {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
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 { Button, Text } from "@theme-ui/components";
|
||||
import { Icon } from "../icons/icon";
|
||||
import { Icons } from "../icons";
|
||||
|
||||
type CheckListItemProps = {
|
||||
title: string;
|
||||
isSelected: boolean;
|
||||
onSelected: () => void;
|
||||
indentLevel?: number;
|
||||
};
|
||||
|
||||
export function CheckListItem(props: CheckListItemProps) {
|
||||
const { title, onSelected, isSelected, indentLevel = 0 } = props;
|
||||
return (
|
||||
<Button
|
||||
variant="list"
|
||||
onClick={onSelected}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
py: 1,
|
||||
px: 1,
|
||||
ml: indentLevel * 2
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
path={isSelected ? Icons.checkCircle : Icons.circle}
|
||||
color={isSelected ? "primary" : "text"}
|
||||
size={16}
|
||||
/>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
ml: 1,
|
||||
fontWeight: 400,
|
||||
color: "text"
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import { FlexScrollContainer } from "../scroll-container";
|
||||
type FilteredListT<T> = {
|
||||
placeholder: string;
|
||||
getAll: () => Array<T>;
|
||||
filter: (items: T[], query: string) => T[];
|
||||
filter?: (items: T[], query: string) => T[];
|
||||
onCreateNewItem?: (title: string) => void;
|
||||
renderItem: (item: T, index: number) => JSX.Element;
|
||||
itemName: string;
|
||||
@@ -57,6 +57,7 @@ export function FilteredList<T>({
|
||||
|
||||
const _filter = useCallback(
|
||||
(query) => {
|
||||
if (!filter) return;
|
||||
setItems(() => {
|
||||
const items = getAll();
|
||||
if (!query) {
|
||||
@@ -83,27 +84,32 @@ export function FilteredList<T>({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
sx={{
|
||||
mt: 1,
|
||||
mb: 1,
|
||||
mr: 1,
|
||||
fontSize: "body",
|
||||
py: "7px",
|
||||
color: "text"
|
||||
}}
|
||||
ref={inputRef}
|
||||
autoFocus
|
||||
placeholder={items.length <= 0 ? `Add a ${itemName}` : placeholder}
|
||||
onChange={(e) => {
|
||||
_filter(e.target.value);
|
||||
}}
|
||||
onKeyUp={async (e) => {
|
||||
if (e.key === "Enter" && noItemsFound) {
|
||||
_createNewItem(query);
|
||||
{(onCreateNewItem || filter) && (
|
||||
<Input
|
||||
sx={{
|
||||
m: 1,
|
||||
width: "auto",
|
||||
fontSize: "body",
|
||||
py: "7px",
|
||||
color: "text"
|
||||
}}
|
||||
ref={inputRef}
|
||||
autoFocus
|
||||
placeholder={
|
||||
items.length <= 0 && onCreateNewItem
|
||||
? `Add a ${itemName}`
|
||||
: placeholder
|
||||
}
|
||||
}}
|
||||
/>
|
||||
onChange={(e) => {
|
||||
_filter(e.target.value);
|
||||
}}
|
||||
onKeyUp={async (e) => {
|
||||
if (e.key === "Enter" && noItemsFound && onCreateNewItem) {
|
||||
_createNewItem(query);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FlexScrollContainer>
|
||||
<Flex
|
||||
|
||||
@@ -38,7 +38,12 @@ import {
|
||||
mdiMagnify,
|
||||
mdiViewDayOutline,
|
||||
mdiViewDashboardOutline,
|
||||
mdiArrowLeft
|
||||
mdiArrowLeft,
|
||||
mdiCheckCircleOutline,
|
||||
mdiCircleOutline,
|
||||
mdiBookOutline,
|
||||
mdiBookmarkOutline,
|
||||
mdiPound
|
||||
} from "@mdi/js";
|
||||
|
||||
export const Icons = {
|
||||
@@ -67,6 +72,12 @@ export const Icons = {
|
||||
chevronUp: mdiChevronUp,
|
||||
chevronRight: mdiChevronRight,
|
||||
|
||||
checkCircle: mdiCheckCircleOutline,
|
||||
circle: mdiCircleOutline,
|
||||
notebook: mdiBookOutline,
|
||||
topic: mdiBookmarkOutline,
|
||||
tag: mdiPound,
|
||||
|
||||
none: "",
|
||||
back: mdiArrowLeft
|
||||
};
|
||||
|
||||
55
extensions/web-clipper/src/components/inline-tag/index.tsx
Normal file
55
extensions/web-clipper/src/components/inline-tag/index.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
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 { Flex, Text } from "@theme-ui/components";
|
||||
import { Icon } from "../icons/icon";
|
||||
import { SchemeColors } from "@notesnook/theme/dist/theme/colorscheme";
|
||||
|
||||
export function InlineTag(props: {
|
||||
title: string;
|
||||
icon: string;
|
||||
iconColor?: keyof SchemeColors;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
const { title, icon, onClick, iconColor = "icon" } = props;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
onClick={onClick}
|
||||
sx={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
bg: "bgSecondary",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "small",
|
||||
p: "3px",
|
||||
pr: 1,
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
bg: "hover"
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Icon path={icon} color={iconColor} size={14} />
|
||||
<Text variant="subBody" sx={{ color: "icon", ml: 1 }}>
|
||||
{title}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import { Icon } from "../icons/icon";
|
||||
import { Icons } from "../icons";
|
||||
import { useAppStore } from "../../stores/app-store";
|
||||
import { Picker } from "../picker";
|
||||
import { CheckListItem } from "../check-list-item";
|
||||
|
||||
type NotePickerProps = {
|
||||
selectedNote?: ItemReference;
|
||||
@@ -95,7 +96,7 @@ export const NotePicker = (props: NotePickerProps) => {
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Picker onClose={close} isOpen={modalVisible}>
|
||||
<Picker onClose={close} onDone={() => {}} isOpen={modalVisible}>
|
||||
<FilteredList
|
||||
getAll={() => notes}
|
||||
filter={(items, query) =>
|
||||
@@ -105,12 +106,13 @@ export const NotePicker = (props: NotePickerProps) => {
|
||||
placeholder={"Search for a note"}
|
||||
refreshItems={() => notes}
|
||||
renderItem={(note) => (
|
||||
<Note
|
||||
note={note}
|
||||
<CheckListItem
|
||||
title={note.title}
|
||||
onSelected={() => {
|
||||
onSelected(note);
|
||||
close();
|
||||
}}
|
||||
isSelected={selectedNote?.id === note.id}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -118,17 +120,3 @@ export const NotePicker = (props: NotePickerProps) => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function Note({
|
||||
note,
|
||||
onSelected
|
||||
}: {
|
||||
note: ItemReference;
|
||||
onSelected: () => void;
|
||||
}) {
|
||||
return (
|
||||
<Button onClick={onSelected} variant="list" sx={{ py: "7px" }}>
|
||||
<Text variant="body">{note.title}</Text>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,100 +17,120 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { useState } from "react";
|
||||
import { Button, Flex, Text } from "@theme-ui/components";
|
||||
import { Flex } from "@theme-ui/components";
|
||||
import { FilteredList } from "../filtered-list";
|
||||
import {
|
||||
NotebookReference,
|
||||
ItemReference,
|
||||
SelectedNotebook
|
||||
SelectedReference
|
||||
} from "../../common/bridge";
|
||||
import { Icon } from "../icons/icon";
|
||||
import { Icons } from "../icons";
|
||||
import { useAppStore } from "../../stores/app-store";
|
||||
import { Picker } from "../picker";
|
||||
import { InlineTag } from "../inline-tag";
|
||||
import { CheckListItem } from "../check-list-item";
|
||||
|
||||
type NotebookPickerProps = {
|
||||
selectedNotebook?: SelectedNotebook;
|
||||
onSelected: (notebook?: SelectedNotebook) => void;
|
||||
selectedItems: SelectedReference[];
|
||||
onSelected: (items?: SelectedReference[]) => void;
|
||||
};
|
||||
export const NotebookPicker = (props: NotebookPickerProps) => {
|
||||
const { selectedNotebook, onSelected } = props;
|
||||
const { onSelected } = props;
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [expanded, setExpanded] = useState<string | null>(null);
|
||||
const notebooks = useAppStore((s) => s.notebooks);
|
||||
const [selectedItems, setSelectedItems] = useState<SelectedReference[]>(
|
||||
props.selectedItems
|
||||
);
|
||||
|
||||
const close = () => {
|
||||
setExpanded(null);
|
||||
setModalVisible(false);
|
||||
};
|
||||
const open = () => setModalVisible(true);
|
||||
const open = () => {
|
||||
setSelectedItems(props.selectedItems);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex sx={{ alignItems: "center" }}>
|
||||
<Button
|
||||
variant="tool"
|
||||
<Flex
|
||||
sx={{
|
||||
border: "1px solid var(--border)",
|
||||
p: 1,
|
||||
gap: 1,
|
||||
borderRadius: "default",
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{props.selectedItems && props.selectedItems.length
|
||||
? props.selectedItems.map((item) => (
|
||||
<InlineTag
|
||||
key={item.id}
|
||||
title={item.title}
|
||||
icon={item.type === "topic" ? Icons.topic : Icons.notebook}
|
||||
onClick={() =>
|
||||
setSelectedItems((items) => {
|
||||
const copy = items.slice();
|
||||
const index = copy.indexOf(item);
|
||||
if (index > -1) copy.splice(index, 1);
|
||||
onSelected(copy);
|
||||
return copy;
|
||||
})
|
||||
}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
<InlineTag
|
||||
title={selectedItems.length ? "Add more" : "Add to notebook"}
|
||||
icon={Icons.plus}
|
||||
iconColor="primary"
|
||||
onClick={open}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={
|
||||
selectedNotebook
|
||||
? `${selectedNotebook.title} > ${selectedNotebook.topic.title}`
|
||||
: `Select a notebook`
|
||||
}
|
||||
>
|
||||
<Text variant="text">
|
||||
{selectedNotebook
|
||||
? `${selectedNotebook.title} > ${selectedNotebook.topic.title}`
|
||||
: `Select a notebook`}
|
||||
</Text>
|
||||
<Icon path={Icons.chevronDown} color="text" size={18} />
|
||||
</Button>
|
||||
{selectedNotebook && (
|
||||
<Button
|
||||
variant="tool"
|
||||
onClick={() => onSelected(undefined)}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
flexShrink: 0,
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
height: 33
|
||||
}}
|
||||
title={"Clear selection"}
|
||||
>
|
||||
<Icon path={Icons.close} color="text" size={16} />
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Picker onClose={close} isOpen={modalVisible}>
|
||||
<Picker
|
||||
onClose={close}
|
||||
onDone={() => {
|
||||
onSelected(selectedItems);
|
||||
close();
|
||||
}}
|
||||
isOpen={modalVisible}
|
||||
>
|
||||
<FilteredList
|
||||
getAll={() => notebooks}
|
||||
getAll={() => useAppStore.getState().notebooks}
|
||||
filter={(items, query) =>
|
||||
items.filter((item) => item.title.toLowerCase().indexOf(query) > -1)
|
||||
}
|
||||
itemName="notebook"
|
||||
placeholder={"Search for a notebook"}
|
||||
refreshItems={() => notebooks}
|
||||
refreshItems={() => useAppStore.getState().notebooks}
|
||||
renderItem={(item) => (
|
||||
<Notebook
|
||||
notebook={item}
|
||||
isExpanded={expanded === item.id}
|
||||
onExpand={(id) => setExpanded(id || null)}
|
||||
onSelected={(notebook) => {
|
||||
onSelected(notebook);
|
||||
close();
|
||||
isTopicSelected={(topic) =>
|
||||
!!selectedItems.find(
|
||||
(n) =>
|
||||
n.id === topic.id &&
|
||||
n.type === "topic" &&
|
||||
n.parentId === item.id
|
||||
)
|
||||
}
|
||||
isSelected={
|
||||
!!selectedItems.find(
|
||||
(n) => n.id === item.id && n.type === "notebook"
|
||||
)
|
||||
}
|
||||
onSelected={(ref) => {
|
||||
setSelectedItems((items) => {
|
||||
const copy = items.slice();
|
||||
const index = copy.findIndex(
|
||||
(n) => n.id === ref.id && n.type === ref.type
|
||||
);
|
||||
if (index > -1) {
|
||||
copy.splice(index, 1);
|
||||
} else {
|
||||
copy.push(ref);
|
||||
}
|
||||
return copy;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -122,12 +142,12 @@ export const NotebookPicker = (props: NotebookPickerProps) => {
|
||||
|
||||
type NotebookProps = {
|
||||
notebook: NotebookReference;
|
||||
isExpanded: boolean;
|
||||
onExpand: (notebookId?: string) => void;
|
||||
onSelected: (notebook: SelectedNotebook) => void;
|
||||
isSelected: boolean;
|
||||
onSelected: (notebook: SelectedReference) => void;
|
||||
isTopicSelected: (topic: ItemReference) => boolean;
|
||||
};
|
||||
function Notebook(props: NotebookProps) {
|
||||
const { notebook, isExpanded, onExpand, onSelected } = props;
|
||||
const { notebook, isSelected, onSelected, isTopicSelected } = props;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
@@ -136,69 +156,39 @@ function Notebook(props: NotebookProps) {
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="list"
|
||||
onClick={() => {
|
||||
if (isExpanded) return onExpand();
|
||||
onExpand(notebook.id);
|
||||
<CheckListItem
|
||||
title={notebook.title}
|
||||
isSelected={isSelected}
|
||||
onSelected={() => {
|
||||
onSelected({
|
||||
id: notebook.id,
|
||||
title: notebook.title,
|
||||
type: "notebook"
|
||||
});
|
||||
}}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
backgroundColor: isExpanded ? "border" : "transparent",
|
||||
py: "7px",
|
||||
px: 1
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 400,
|
||||
color: "var(--paragraph)"
|
||||
}}
|
||||
>
|
||||
{notebook.title}
|
||||
</Text>
|
||||
<Icon
|
||||
path={isExpanded ? Icons.chevronUp : Icons.chevronDown}
|
||||
color="text"
|
||||
size={18}
|
||||
/>
|
||||
</Button>
|
||||
/>
|
||||
|
||||
{isExpanded ? (
|
||||
<FilteredList
|
||||
getAll={() => notebook.topics}
|
||||
filter={(items, query) =>
|
||||
items.filter((item) => item.title.toLowerCase().indexOf(query) > -1)
|
||||
}
|
||||
itemName="topic"
|
||||
placeholder={"Search for a topic"}
|
||||
refreshItems={() => notebook.topics}
|
||||
renderItem={(topic) => (
|
||||
<Topic
|
||||
topic={topic}
|
||||
onSelected={() => {
|
||||
onSelected({ id: notebook.id, title: notebook.title, topic });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
<FilteredList
|
||||
getAll={() => notebook.topics}
|
||||
itemName="topic"
|
||||
placeholder={"Search for a topic"}
|
||||
refreshItems={() => notebook.topics}
|
||||
renderItem={(topic) => (
|
||||
<CheckListItem
|
||||
title={topic.title}
|
||||
isSelected={isTopicSelected(topic)}
|
||||
indentLevel={1}
|
||||
onSelected={() => {
|
||||
onSelected({
|
||||
id: topic.id,
|
||||
title: topic.title,
|
||||
type: "topic",
|
||||
parentId: notebook.id
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
type TopicProps = {
|
||||
topic: ItemReference;
|
||||
onSelected: () => void;
|
||||
};
|
||||
function Topic(props: TopicProps) {
|
||||
const { topic, onSelected } = props;
|
||||
return (
|
||||
<Button variant="list" onClick={onSelected} sx={{ pl: 3, py: "7px" }}>
|
||||
<Text variant="text">{topic.title}</Text>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { PropsWithChildren } from "react";
|
||||
import Modal from "react-modal";
|
||||
import { Flex } from "@theme-ui/components";
|
||||
import { Button, Flex } from "@theme-ui/components";
|
||||
import { ThemeProvider } from "../theme-provider";
|
||||
Modal.setAppElement("#root");
|
||||
|
||||
@@ -30,26 +30,27 @@ const customStyles = {
|
||||
bottom: "auto",
|
||||
marginRight: "-50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
boxShadow: "0px 1px 10px var(--info)",
|
||||
boxShadow: "0px 1px 10px #00000055",
|
||||
border: "none",
|
||||
borderRadius: 5,
|
||||
backgroundColor: "var(--background)",
|
||||
padding: "10px",
|
||||
|
||||
height: "80vh",
|
||||
width: "85vw",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden"
|
||||
overflow: "hidden",
|
||||
padding: 0
|
||||
} as const
|
||||
};
|
||||
|
||||
type PickerProps = {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onDone: () => void;
|
||||
};
|
||||
export const Picker = (props: PropsWithChildren<PickerProps>) => {
|
||||
const { children, isOpen, onClose } = props;
|
||||
const { children, isOpen, onClose, onDone } = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -66,10 +67,25 @@ export const Picker = (props: PropsWithChildren<PickerProps>) => {
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
overflow: "hidden"
|
||||
overflow: "hidden",
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
flex: 1,
|
||||
padding: 2
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Flex>
|
||||
<Flex sx={{ bg: "bgSecondary", p: 1, justifyContent: "end" }}>
|
||||
<Button variant="dialog" onClick={onDone}>
|
||||
Done
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</ThemeProvider>
|
||||
</Modal>
|
||||
|
||||
@@ -17,29 +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/>.
|
||||
*/
|
||||
import { useState } from "react";
|
||||
import { Button, Flex, Text } from "@theme-ui/components";
|
||||
import { Flex } from "@theme-ui/components";
|
||||
import { FilteredList } from "../filtered-list";
|
||||
import { ItemReference } from "../../common/bridge";
|
||||
import { Icon } from "../icons/icon";
|
||||
import { Icons } from "../icons";
|
||||
import { useAppStore } from "../../stores/app-store";
|
||||
import { Picker } from "../picker";
|
||||
import { InlineTag } from "../inline-tag";
|
||||
import { CheckListItem } from "../check-list-item";
|
||||
|
||||
type TagPickerProps = {
|
||||
selectedTags: string[];
|
||||
onSelected: (tag: string) => void;
|
||||
onDeselected: (tag: string) => void;
|
||||
onSelected: (tags: string[]) => void;
|
||||
};
|
||||
export const TagPicker = (props: TagPickerProps) => {
|
||||
const { selectedTags, onSelected, onDeselected } = props;
|
||||
const { onSelected } = props;
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const tags = useAppStore((s) => s.tags);
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>(
|
||||
props.selectedTags || []
|
||||
);
|
||||
|
||||
const close = () => {
|
||||
setModalVisible(false);
|
||||
};
|
||||
const open = () => setModalVisible(true);
|
||||
|
||||
const open = () => {
|
||||
setSelectedTags(props.selectedTags || []);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -47,59 +52,66 @@ export const TagPicker = (props: TagPickerProps) => {
|
||||
sx={{
|
||||
border: "2px solid var(--border)",
|
||||
p: 1,
|
||||
pb: 0,
|
||||
borderRadius: "default",
|
||||
flexWrap: "wrap"
|
||||
flexWrap: "wrap",
|
||||
gap: 1
|
||||
}}
|
||||
>
|
||||
{selectedTags.length
|
||||
? selectedTags.map((tag) => (
|
||||
{props.selectedTags.length
|
||||
? props.selectedTags.map((tag) => (
|
||||
<InlineTag
|
||||
key={tag}
|
||||
tag={tag}
|
||||
onDeselected={() => {
|
||||
onDeselected(tag);
|
||||
icon={Icons.tag}
|
||||
title={tag}
|
||||
onClick={() => {
|
||||
setSelectedTags((items) => {
|
||||
const copy = items.slice();
|
||||
const index = copy.indexOf(tag);
|
||||
if (index > -1) copy.splice(index, 1);
|
||||
onSelected(copy);
|
||||
return copy;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
<Flex
|
||||
<InlineTag
|
||||
icon={Icons.plus}
|
||||
title={"Assign a tag"}
|
||||
iconColor="primary"
|
||||
onClick={open}
|
||||
sx={{
|
||||
bg: "bgSecondary",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "small",
|
||||
mr: 1,
|
||||
px: 1,
|
||||
mb: 1,
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
bg: "hover"
|
||||
}
|
||||
}}
|
||||
title="Click to assign more tags"
|
||||
>
|
||||
<Icon path={Icons.plus} size={12} color="fontTertiary" />
|
||||
<Text variant="subBody" sx={{ ml: "2px", color: "icon" }}>
|
||||
Assign a tag
|
||||
</Text>
|
||||
</Flex>
|
||||
/>
|
||||
</Flex>
|
||||
<Picker onClose={close} isOpen={modalVisible}>
|
||||
<Picker
|
||||
onClose={close}
|
||||
onDone={() => {
|
||||
onSelected(selectedTags);
|
||||
close();
|
||||
}}
|
||||
isOpen={modalVisible}
|
||||
>
|
||||
<FilteredList
|
||||
getAll={() => tags}
|
||||
getAll={() => useAppStore.getState().tags}
|
||||
filter={(items, query) =>
|
||||
items.filter((item) => item.title.toLowerCase().indexOf(query) > -1)
|
||||
}
|
||||
itemName="tag"
|
||||
placeholder={"Search for a tag"}
|
||||
onCreateNewItem={(tag) => onSelected(tag)}
|
||||
refreshItems={() => tags}
|
||||
refreshItems={() => useAppStore.getState().tags}
|
||||
renderItem={(tag) => (
|
||||
<Tag
|
||||
tag={tag}
|
||||
<CheckListItem
|
||||
title={`#${tag.title}`}
|
||||
onSelected={() => {
|
||||
onSelected(tag.title);
|
||||
setSelectedTags((items) => {
|
||||
const copy = items.slice();
|
||||
const index = copy.indexOf(tag.title);
|
||||
if (index > -1) {
|
||||
copy.splice(index, 1);
|
||||
} else {
|
||||
copy.push(tag.title);
|
||||
}
|
||||
return copy;
|
||||
});
|
||||
}}
|
||||
isSelected={selectedTags.indexOf(tag.title) > -1}
|
||||
/>
|
||||
@@ -109,64 +121,3 @@ export const TagPicker = (props: TagPickerProps) => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type TagProps = {
|
||||
tag: ItemReference;
|
||||
isSelected: boolean;
|
||||
onSelected: () => void;
|
||||
};
|
||||
function Tag(props: TagProps) {
|
||||
const { tag, onSelected, isSelected } = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="list"
|
||||
onClick={onSelected}
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
py: "7px",
|
||||
px: 1
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 400,
|
||||
color: "var(--paragraph)"
|
||||
}}
|
||||
>
|
||||
#{tag.title}
|
||||
</Text>
|
||||
{isSelected ? <Icon path={Icons.check} color="text" size={14} /> : null}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function InlineTag(props: { tag: string; onDeselected: () => void }) {
|
||||
const { tag, onDeselected } = props;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
onClick={onDeselected}
|
||||
sx={{
|
||||
bg: "bgSecondary",
|
||||
border: "1px solid var(--border)",
|
||||
borderRadius: "small",
|
||||
mr: 1,
|
||||
px: 1,
|
||||
mb: 1,
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
bg: "hover"
|
||||
}
|
||||
}}
|
||||
title="Click to remove"
|
||||
>
|
||||
<Text variant="subBody" sx={{ color: "icon" }}>
|
||||
#{tag}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,43 +26,38 @@ import {
|
||||
WEB_EXTENSION_CHANNEL_EVENTS
|
||||
} from "../common/bridge";
|
||||
|
||||
let mainPort: MessagePort | undefined;
|
||||
|
||||
browser.runtime.onConnect.addListener((port) => {
|
||||
if (mainPort) {
|
||||
const server: Remote<Server> = wrap<Server>(mainPort);
|
||||
expose(
|
||||
{
|
||||
login: () => server.login(),
|
||||
getNotes: () => server.getNotes(),
|
||||
getNotebooks: () => server.getNotebooks(),
|
||||
getTags: () => server.getTags(),
|
||||
saveClip: (clip: Clip) => server.saveClip(clip)
|
||||
},
|
||||
createEndpoint(port)
|
||||
);
|
||||
port.postMessage({ success: true });
|
||||
} else {
|
||||
port.postMessage({ success: false });
|
||||
}
|
||||
});
|
||||
window.addEventListener("message", (ev) => {
|
||||
const { type } = ev.data;
|
||||
switch (type) {
|
||||
case WEB_EXTENSION_CHANNEL_EVENTS.ON_CREATED:
|
||||
if (ev.ports.length) {
|
||||
const mainPort = ev.ports.at(0);
|
||||
if (mainPort) {
|
||||
expose(new BackgroundGateway(), mainPort);
|
||||
const server: Remote<Server> = wrap<Server>(mainPort);
|
||||
expose(
|
||||
{
|
||||
login: () => server.login(),
|
||||
getNotes: () => server.getNotes(),
|
||||
getNotebooks: () => server.getNotebooks(),
|
||||
getTags: () => server.getTags(),
|
||||
saveClip: (clip: Clip) => server.saveClip(clip)
|
||||
},
|
||||
createEndpoint(port)
|
||||
);
|
||||
port.postMessage({ success: true });
|
||||
} else {
|
||||
port.postMessage({ success: false });
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("message", (ev) => {
|
||||
const { type } = ev.data;
|
||||
switch (type) {
|
||||
case WEB_EXTENSION_CHANNEL_EVENTS.ON_CREATED:
|
||||
if (ev.ports.length) {
|
||||
const [port] = ev.ports;
|
||||
mainPort = port;
|
||||
expose(new BackgroundGateway(), port);
|
||||
browser.runtime.sendMessage(undefined, { type: "start_connection" });
|
||||
}
|
||||
break;
|
||||
}
|
||||
window.postMessage({ type: WEB_EXTENSION_CHANNEL_EVENTS.ON_READY }, "*");
|
||||
});
|
||||
|
||||
window.postMessage({ type: WEB_EXTENSION_CHANNEL_EVENTS.ON_READY }, "*");
|
||||
|
||||
class BackgroundGateway implements Gateway {
|
||||
connect() {
|
||||
return {
|
||||
|
||||
@@ -61,7 +61,9 @@ export const useAppStore = create<AppStore>((set) => ({
|
||||
|
||||
if (!notesnook) {
|
||||
set({ isLoggingIn: false });
|
||||
return;
|
||||
throw new Error(
|
||||
"Please refresh the Notesnook web app to connect with the Web Clipper."
|
||||
);
|
||||
}
|
||||
|
||||
const user = await notesnook.login();
|
||||
|
||||
@@ -26,7 +26,7 @@ import { NotebookPicker } from "../components/notebook-picker";
|
||||
import { TagPicker } from "../components/tag-picker";
|
||||
import {
|
||||
ItemReference,
|
||||
SelectedNotebook,
|
||||
SelectedReference,
|
||||
ClipArea,
|
||||
ClipMode,
|
||||
ClipData
|
||||
@@ -39,6 +39,10 @@ import { FlexScrollContainer } from "../components/scroll-container";
|
||||
import { DEFAULT_SETTINGS, SETTINGS_KEY } from "./settings";
|
||||
import type { Config } from "@notesnook/clipper/dist/types";
|
||||
|
||||
const ERROR_MAP: Record<string, string> = {
|
||||
"Could not establish connection. Receiving end does not exist.":
|
||||
"Please refresh this web page and try again. If the error persists, it means you don't have the required permission."
|
||||
};
|
||||
const clipAreas: { name: string; id: ClipArea; icon: string }[] = [
|
||||
{
|
||||
name: "Full page",
|
||||
@@ -92,6 +96,7 @@ export function Main() {
|
||||
|
||||
const [settings] = usePersistentState<Config>(SETTINGS_KEY, DEFAULT_SETTINGS);
|
||||
const [title, setTitle] = useState<string>();
|
||||
const [hasPermission, setHasPermission] = useState<boolean>(false);
|
||||
const [url, setUrl] = useState<string>();
|
||||
const [clipNonce, setClipNonce] = useState(0);
|
||||
const [clipMode, setClipMode] = usePersistentState<ClipMode>(
|
||||
@@ -104,15 +109,18 @@ export function Main() {
|
||||
);
|
||||
const [isClipping, setIsClipping] = useState(false);
|
||||
const [note, setNote] = usePersistentState<ItemReference>("note");
|
||||
const [notebook, setNotebook] =
|
||||
usePersistentState<SelectedNotebook>("notebook");
|
||||
const [refs, setRefs] = usePersistentState<SelectedReference[]>("refs", []);
|
||||
const [tags, setTags] = usePersistentState<string[]>("tags", []);
|
||||
const [clipData, setClipData] = useState<ClipData>();
|
||||
const pageTitle = useRef<string>();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const [tab] = await browser.tabs.query({ active: true });
|
||||
const [tab] = await browser.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
windowType: "normal"
|
||||
});
|
||||
|
||||
setTitle(tab?.title ? tab.title : "Untitled");
|
||||
setUrl(tab?.url);
|
||||
@@ -123,6 +131,13 @@ export function Main() {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (!clipArea || !clipMode) return;
|
||||
if (
|
||||
!isPremium &&
|
||||
(clipMode === "complete" || clipMode === "screenshot")
|
||||
) {
|
||||
setClipMode("simplified");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsClipping(true);
|
||||
@@ -134,7 +149,58 @@ export function Main() {
|
||||
setIsClipping(false);
|
||||
}
|
||||
})();
|
||||
}, [clipArea, clipMode, clipNonce]);
|
||||
}, [isPremium, clipArea, clipMode, clipNonce]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (!settings || !settings.corsProxy) return;
|
||||
setHasPermission(
|
||||
await browser.permissions.contains({
|
||||
origins: [`${settings.corsProxy}/*`]
|
||||
})
|
||||
);
|
||||
})();
|
||||
}, [settings]);
|
||||
|
||||
if (!hasPermission && !!settings?.corsProxy) {
|
||||
return (
|
||||
<FlexScrollContainer style={{ maxHeight: 560 }}>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
p: 2,
|
||||
width: 320,
|
||||
backgroundColor: "background"
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
variant="subtitle"
|
||||
sx={{ mt: 2, mb: 1, color: "icon", fontSize: "body" }}
|
||||
>
|
||||
Permission required
|
||||
</Text>
|
||||
<Text
|
||||
variant="body"
|
||||
sx={{ mt: 2, mb: 1, color: "icon", fontSize: "body" }}
|
||||
>
|
||||
Permission is required to use the CORS proxy: {settings.corsProxy}
|
||||
</Text>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
if (!settings.corsProxy) return;
|
||||
setHasPermission(
|
||||
await browser.permissions.request({
|
||||
origins: [`${settings.corsProxy}/*`]
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
Grant permission
|
||||
</Button>
|
||||
</Flex>
|
||||
</FlexScrollContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FlexScrollContainer style={{ maxHeight: 560 }}>
|
||||
@@ -290,9 +356,11 @@ export function Main() {
|
||||
setClipNonce((s) => ++s);
|
||||
}}
|
||||
>
|
||||
{error}
|
||||
{ERROR_MAP[error] || error}
|
||||
<br />
|
||||
Click here to retry.
|
||||
<Text sx={{ fontSize: 11, color: "error" }}>
|
||||
Click here to try again.
|
||||
</Text>
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -303,7 +371,7 @@ export function Main() {
|
||||
Organization
|
||||
</Text>
|
||||
|
||||
{notebook || tags?.length ? null : (
|
||||
{refs?.length || tags?.length ? null : (
|
||||
<NotePicker
|
||||
selectedNote={note}
|
||||
onSelected={(note) => setNote(note)}
|
||||
@@ -311,34 +379,19 @@ export function Main() {
|
||||
)}
|
||||
{note ? null : (
|
||||
<>
|
||||
{notebook || tags?.length ? null : (
|
||||
{refs?.length || tags?.length ? null : (
|
||||
<Text variant="subBody" sx={{ my: 1, textAlign: "center" }}>
|
||||
— or —
|
||||
</Text>
|
||||
)}
|
||||
<NotebookPicker
|
||||
selectedNotebook={notebook}
|
||||
onSelected={(notebook) => setNotebook(notebook)}
|
||||
selectedItems={refs || []}
|
||||
onSelected={(items) => setRefs(items)}
|
||||
/>
|
||||
<Box sx={{ mt: 1 }} />
|
||||
<TagPicker
|
||||
selectedTags={tags || []}
|
||||
onDeselected={(tag) => {
|
||||
setTags((tags) => {
|
||||
const copy = tags?.slice() || [];
|
||||
copy.splice(copy.indexOf(tag), 1);
|
||||
return copy;
|
||||
});
|
||||
}}
|
||||
onSelected={(tag) => {
|
||||
setTags((tags) => {
|
||||
const copy = tags?.slice() || [];
|
||||
if (copy.indexOf(tag) > -1) {
|
||||
copy.splice(copy.indexOf(tag), 1);
|
||||
} else copy.push(tag);
|
||||
return copy;
|
||||
});
|
||||
}}
|
||||
onSelected={(tags) => setTags(tags)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
@@ -360,12 +413,21 @@ export function Main() {
|
||||
mode: clipMode,
|
||||
tags,
|
||||
note,
|
||||
notebook,
|
||||
refs,
|
||||
pageTitle: pageTitle.current,
|
||||
...clipData
|
||||
});
|
||||
|
||||
setClipData(undefined);
|
||||
|
||||
await browser.notifications?.create({
|
||||
title: "Clip saved!",
|
||||
message: "Open the Notesnook app to view the result.",
|
||||
type: "basic",
|
||||
iconUrl: browser.runtime.getURL("256x256.png"),
|
||||
isClickable: false
|
||||
});
|
||||
|
||||
window.close();
|
||||
}}
|
||||
>
|
||||
@@ -406,9 +468,24 @@ export async function clip(
|
||||
return { data: clipData };
|
||||
}
|
||||
|
||||
const [tab] = await browser.tabs.query({ active: true });
|
||||
const [tab] = await browser.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
windowType: "normal"
|
||||
});
|
||||
if (!tab || !tab.id) return;
|
||||
|
||||
if (browser.scripting) {
|
||||
await browser.scripting.executeScript({
|
||||
files: ["contentScript.bundle.js"],
|
||||
target: { tabId: tab.id }
|
||||
});
|
||||
} else {
|
||||
await browser.tabs.executeScript(tab.id, {
|
||||
file: "contentScript.bundle.js"
|
||||
});
|
||||
}
|
||||
|
||||
if (area === "visible" && mode === "screenshot") {
|
||||
if (!tab.height || !tab.width) return;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export function Settings() {
|
||||
backgroundColor: "background"
|
||||
}}
|
||||
as="form"
|
||||
onSubmit={(e) => {
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const form = new FormData(e.target as HTMLFormElement);
|
||||
@@ -56,6 +56,10 @@ export function Settings() {
|
||||
corsProxy = `${url.protocol}//${url.hostname}`;
|
||||
}
|
||||
|
||||
await browser.permissions.request({
|
||||
origins: [`${corsProxy}/*`]
|
||||
});
|
||||
|
||||
saveSettings({
|
||||
corsProxy
|
||||
});
|
||||
|
||||
5
fastlane/metadata/android/en-US/changelogs/10234.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/10234.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
- Fix a crash when tryin to upload attachments
|
||||
- Fix editor not rendered when enter foreground after a long time on iOS
|
||||
- Increased hit area for outline list to make toggling outline list items easier
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -29,7 +29,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "playwright test"
|
||||
"test": "playwright test",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/streetwriters/notesnook/issues"
|
||||
|
||||
24
packages/clipper/patches/css-what+6.1.0.patch
Normal file
24
packages/clipper/patches/css-what+6.1.0.patch
Normal file
@@ -0,0 +1,24 @@
|
||||
diff --git a/node_modules/css-what/lib/commonjs/stringify.js b/node_modules/css-what/lib/commonjs/stringify.js
|
||||
index 158b180..89b5b6c 100644
|
||||
--- a/node_modules/css-what/lib/commonjs/stringify.js
|
||||
+++ b/node_modules/css-what/lib/commonjs/stringify.js
|
||||
@@ -11,7 +11,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.stringify = void 0;
|
||||
var types_1 = require("./types");
|
||||
-var attribValChars = ["\\", '"'];
|
||||
+var attribValChars = ["\\", '"', "%", "'"];
|
||||
var pseudoValChars = __spreadArray(__spreadArray([], attribValChars, true), ["(", ")"], false);
|
||||
var charsToEscapeInAttributeValue = new Set(attribValChars.map(function (c) { return c.charCodeAt(0); }));
|
||||
var charsToEscapeInPseudoValue = new Set(pseudoValChars.map(function (c) { return c.charCodeAt(0); }));
|
||||
diff --git a/node_modules/css-what/lib/es/stringify.js b/node_modules/css-what/lib/es/stringify.js
|
||||
index 5f3b8ef..0ec34f7 100644
|
||||
--- a/node_modules/css-what/lib/es/stringify.js
|
||||
+++ b/node_modules/css-what/lib/es/stringify.js
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SelectorType, AttributeAction } from "./types";
|
||||
-const attribValChars = ["\\", '"'];
|
||||
+const attribValChars = ["\\", '"', "%", "'"];
|
||||
const pseudoValChars = [...attribValChars, "(", ")"];
|
||||
const charsToEscapeInAttributeValue = new Set(attribValChars.map((c) => c.charCodeAt(0)));
|
||||
const charsToEscapeInPseudoValue = new Set(pseudoValChars.map((c) => c.charCodeAt(0)));
|
||||
@@ -463,7 +463,7 @@ async function getPage(
|
||||
fetchOptions: resolveFetchOptions(config),
|
||||
inlineOptions: {
|
||||
fonts: false,
|
||||
images: true,
|
||||
images: styles,
|
||||
stylesheets: styles
|
||||
},
|
||||
styles,
|
||||
|
||||
@@ -34,11 +34,30 @@ export default class Subscriptions {
|
||||
await http.delete(`${hosts.SUBSCRIPTIONS_HOST}/subscriptions`, token);
|
||||
}
|
||||
|
||||
async refund() {
|
||||
const token = await this._tokenManager.getAccessToken();
|
||||
if (!token) return;
|
||||
await http.post(
|
||||
`${hosts.SUBSCRIPTIONS_HOST}/subscriptions/refund`,
|
||||
null,
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
async transactions() {
|
||||
const token = await this._tokenManager.getAccessToken();
|
||||
if (!token) return;
|
||||
return await http.get(
|
||||
`${hosts.SUBSCRIPTIONS_HOST}/subscriptions/transactions`,
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
async updateUrl() {
|
||||
const token = await this._tokenManager.getAccessToken();
|
||||
if (!token) return;
|
||||
return await http.get(
|
||||
`${hosts.SUBSCRIPTIONS_HOST}/subscriptions/update_url`,
|
||||
`${hosts.SUBSCRIPTIONS_HOST}/subscriptions/update`,
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { migrateItem } from "../../migrations";
|
||||
import setManipulator from "../../utils/set";
|
||||
import { logger } from "../../logger";
|
||||
import { isHTMLEqual } from "../../utils/html-diff";
|
||||
import { EV, EVENTS } from "../../common";
|
||||
|
||||
class Merger {
|
||||
/**
|
||||
@@ -225,8 +226,8 @@ class Merger {
|
||||
if (!type || !item || !definition) return;
|
||||
|
||||
if (!this.key) this.key = await this._db.user.getEncryptionKey();
|
||||
if (!this.key.key || !this.key.salt) {
|
||||
await this._db.user.logout(true, "User encryption key not generated.");
|
||||
if (!this.key || !this.key.key || !this.key.salt) {
|
||||
EV.publish(EVENTS.userSessionExpired);
|
||||
throw new Error("User encryption key not generated. Please relogin.");
|
||||
}
|
||||
|
||||
|
||||
@@ -347,11 +347,12 @@ export default class Notes extends Collection {
|
||||
|
||||
for (const noteId of noteIds) {
|
||||
const note = this.note(noteId);
|
||||
if (!note || note.deleted || !note.notebooks) {
|
||||
if (!note || note.deleted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (topicId) {
|
||||
if (!note.notebooks) continue;
|
||||
const { notebooks } = note;
|
||||
|
||||
const notebook = findById(notebooks, notebookId);
|
||||
|
||||
423
packages/editor-mobile/package-lock.json
generated
423
packages/editor-mobile/package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"name": "@notesnook/editor-mobile",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@mdi/js": "^6.9.96",
|
||||
"@mdi/react": "^1.6.0",
|
||||
"framer-motion": "^6.5.1",
|
||||
@@ -85,7 +86,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.18.6"
|
||||
},
|
||||
@@ -370,7 +370,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
|
||||
"integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.18.6"
|
||||
},
|
||||
@@ -492,7 +491,6 @@
|
||||
"version": "7.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
|
||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -501,7 +499,6 @@
|
||||
"version": "7.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -548,7 +545,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"chalk": "^2.0.0",
|
||||
@@ -562,7 +558,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
@@ -574,7 +569,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -588,7 +582,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -596,14 +589,12 @@
|
||||
"node_modules/@babel/highlight/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/@babel/highlight/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
@@ -612,7 +603,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -621,7 +611,6 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
@@ -2023,7 +2012,6 @@
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
|
||||
"integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
@@ -2083,7 +2071,6 @@
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.0.tgz",
|
||||
"integrity": "sha512-uR7NWq2VNFnDi7EYqiRz2Jv/VQIu38tu64Zy8TX2nQFQ6etJ9V/Rr2msW8BS132mum2rL645qpDrLtAJtVpuow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.19.4",
|
||||
"@babel/helper-validator-identifier": "^7.19.1",
|
||||
@@ -2386,6 +2373,59 @@
|
||||
"postcss-selector-parser": "^6.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
|
||||
"integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/hash": "^0.9.1",
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/serialize": "^1.1.2",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"convert-source-map": "^1.5.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.5.7",
|
||||
"stylis": "4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/cache": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
|
||||
"integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/sheet": "^1.2.2",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"@emotion/weak-memoize": "^0.3.1",
|
||||
"stylis": "4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/cache/node_modules/@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/hash": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
|
||||
"integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
|
||||
@@ -2401,6 +2441,74 @@
|
||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@emotion/react": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.0.tgz",
|
||||
"integrity": "sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.11.0",
|
||||
"@emotion/cache": "^11.11.0",
|
||||
"@emotion/serialize": "^1.1.2",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"@emotion/weak-memoize": "^0.3.1",
|
||||
"hoist-non-react-statics": "^3.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/serialize": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz",
|
||||
"integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==",
|
||||
"dependencies": {
|
||||
"@emotion/hash": "^0.9.1",
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/unitless": "^0.8.1",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/serialize/node_modules/@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/sheet": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
|
||||
"integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA=="
|
||||
},
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
|
||||
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
|
||||
},
|
||||
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
|
||||
"integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/utils": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
|
||||
"integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg=="
|
||||
},
|
||||
"node_modules/@emotion/weak-memoize": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
|
||||
"integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
|
||||
@@ -4235,8 +4343,7 @@
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
|
||||
},
|
||||
"node_modules/@types/prettier": {
|
||||
"version": "2.7.2",
|
||||
@@ -5520,7 +5627,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"cosmiconfig": "^7.0.0",
|
||||
@@ -5895,7 +6001,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -6357,8 +6462,7 @@
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
@@ -6420,7 +6524,6 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
|
||||
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
@@ -6906,8 +7009,7 @@
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
"version": "1.0.8",
|
||||
@@ -7497,7 +7599,6 @@
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
@@ -7626,7 +7727,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -8878,6 +8978,11 @@
|
||||
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
},
|
||||
"node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
@@ -9249,8 +9354,7 @@
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/function.prototype.name": {
|
||||
"version": "1.1.5",
|
||||
@@ -9511,7 +9615,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
@@ -9590,6 +9693,19 @@
|
||||
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
|
||||
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/hoopy": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||
@@ -9901,7 +10017,6 @@
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
@@ -9917,7 +10032,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -10037,8 +10151,7 @@
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"node_modules/is-bigint": {
|
||||
"version": "1.0.4",
|
||||
@@ -10108,7 +10221,6 @@
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
|
||||
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
@@ -12766,8 +12878,7 @@
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema": {
|
||||
"version": "0.4.0",
|
||||
@@ -12915,8 +13026,7 @@
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"node_modules/loader-runner": {
|
||||
"version": "4.3.0",
|
||||
@@ -13783,7 +13893,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"callsites": "^3.0.0"
|
||||
},
|
||||
@@ -13795,7 +13904,6 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
@@ -13962,8 +14070,7 @@
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
@@ -13975,7 +14082,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -16125,8 +16231,7 @@
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/regenerator-transform": {
|
||||
"version": "0.15.0",
|
||||
@@ -16266,7 +16371,6 @@
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.9.0",
|
||||
"path-parse": "^1.0.7",
|
||||
@@ -17237,6 +17341,11 @@
|
||||
"postcss": "^8.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -17266,7 +17375,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -17661,7 +17769,6 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -19055,7 +19162,6 @@
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
@@ -19160,7 +19266,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
|
||||
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.18.6"
|
||||
}
|
||||
@@ -19373,7 +19478,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
|
||||
"integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.18.6"
|
||||
}
|
||||
@@ -19464,14 +19568,12 @@
|
||||
"@babel/helper-string-parser": {
|
||||
"version": "7.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
|
||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw=="
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
|
||||
},
|
||||
"@babel/helper-validator-option": {
|
||||
"version": "7.18.6",
|
||||
@@ -19506,7 +19608,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
|
||||
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"chalk": "^2.0.0",
|
||||
@@ -19517,7 +19618,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
@@ -19526,7 +19626,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@@ -19537,7 +19636,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@@ -19545,26 +19643,22 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
@@ -20501,7 +20595,6 @@
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
|
||||
"integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
}
|
||||
@@ -20549,7 +20642,6 @@
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.0.tgz",
|
||||
"integrity": "sha512-uR7NWq2VNFnDi7EYqiRz2Jv/VQIu38tu64Zy8TX2nQFQ6etJ9V/Rr2msW8BS132mum2rL645qpDrLtAJtVpuow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.19.4",
|
||||
"@babel/helper-validator-identifier": "^7.19.1",
|
||||
@@ -20702,6 +20794,60 @@
|
||||
"integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==",
|
||||
"dev": true
|
||||
},
|
||||
"@emotion/babel-plugin": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
|
||||
"integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "^7.16.7",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/hash": "^0.9.1",
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/serialize": "^1.1.2",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"convert-source-map": "^1.5.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.5.7",
|
||||
"stylis": "4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/cache": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
|
||||
"integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
|
||||
"requires": {
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/sheet": "^1.2.2",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"@emotion/weak-memoize": "^0.3.1",
|
||||
"stylis": "4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/hash": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
|
||||
"integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ=="
|
||||
},
|
||||
"@emotion/is-prop-valid": {
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
|
||||
@@ -20717,6 +20863,65 @@
|
||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
|
||||
"optional": true
|
||||
},
|
||||
"@emotion/react": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.0.tgz",
|
||||
"integrity": "sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.11.0",
|
||||
"@emotion/cache": "^11.11.0",
|
||||
"@emotion/serialize": "^1.1.2",
|
||||
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"@emotion/weak-memoize": "^0.3.1",
|
||||
"hoist-non-react-statics": "^3.3.1"
|
||||
}
|
||||
},
|
||||
"@emotion/serialize": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz",
|
||||
"integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.9.1",
|
||||
"@emotion/memoize": "^0.8.1",
|
||||
"@emotion/unitless": "^0.8.1",
|
||||
"@emotion/utils": "^1.2.1",
|
||||
"csstype": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/sheet": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
|
||||
"integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA=="
|
||||
},
|
||||
"@emotion/unitless": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
|
||||
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
|
||||
},
|
||||
"@emotion/use-insertion-effect-with-fallbacks": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
|
||||
"integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw=="
|
||||
},
|
||||
"@emotion/utils": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
|
||||
"integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg=="
|
||||
},
|
||||
"@emotion/weak-memoize": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
|
||||
"integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww=="
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
|
||||
@@ -22141,8 +22346,7 @@
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
|
||||
},
|
||||
"@types/prettier": {
|
||||
"version": "2.7.2",
|
||||
@@ -23132,7 +23336,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"cosmiconfig": "^7.0.0",
|
||||
@@ -23432,8 +23635,7 @@
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
|
||||
},
|
||||
"camel-case": {
|
||||
"version": "4.1.2",
|
||||
@@ -23800,8 +24002,7 @@
|
||||
"convert-source-map": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.5.0",
|
||||
@@ -23846,7 +24047,6 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz",
|
||||
"integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
@@ -24181,8 +24381,7 @@
|
||||
"csstype": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.8",
|
||||
@@ -24630,7 +24829,6 @@
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
@@ -24740,8 +24938,7 @@
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "2.0.0",
|
||||
@@ -25691,6 +25888,11 @@
|
||||
"pkg-dir": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
},
|
||||
"find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
@@ -25951,8 +26153,7 @@
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"function.prototype.name": {
|
||||
"version": "1.1.5",
|
||||
@@ -26146,7 +26347,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
@@ -26198,6 +26398,21 @@
|
||||
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
|
||||
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"hoopy": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
|
||||
@@ -26437,7 +26652,6 @@
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
@@ -26446,8 +26660,7 @@
|
||||
"resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -26536,8 +26749,7 @@
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||
},
|
||||
"is-bigint": {
|
||||
"version": "1.0.4",
|
||||
@@ -26586,7 +26798,6 @@
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
|
||||
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
@@ -28613,8 +28824,7 @@
|
||||
"json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.4.0",
|
||||
@@ -28732,8 +28942,7 @@
|
||||
"lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"loader-runner": {
|
||||
"version": "4.3.0",
|
||||
@@ -29384,7 +29593,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"callsites": "^3.0.0"
|
||||
}
|
||||
@@ -29393,7 +29601,6 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
@@ -29523,8 +29730,7 @@
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
@@ -29535,8 +29741,7 @@
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
@@ -30947,8 +31152,7 @@
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"regenerator-transform": {
|
||||
"version": "0.15.0",
|
||||
@@ -31060,7 +31264,6 @@
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.9.0",
|
||||
"path-parse": "^1.0.7",
|
||||
@@ -31785,6 +31988,11 @@
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
}
|
||||
},
|
||||
"stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
@@ -31807,8 +32015,7 @@
|
||||
"supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
||||
},
|
||||
"svg-parser": {
|
||||
"version": "2.0.4",
|
||||
@@ -32109,8 +32316,7 @@
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
@@ -33202,8 +33408,7 @@
|
||||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"mdi-react": "9.1.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"zustand": "^3.6.8"
|
||||
"zustand": "^3.6.8",
|
||||
"@emotion/react": "^11.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/react-scripts/config/webpack.config.js b/node_modules/react-scripts/config/webpack.config.js
|
||||
index e465d8e..18b7317 100644
|
||||
index e465d8e..5e3771c 100644
|
||||
--- a/node_modules/react-scripts/config/webpack.config.js
|
||||
+++ b/node_modules/react-scripts/config/webpack.config.js
|
||||
@@ -106,6 +106,9 @@ module.exports = function (webpackEnv) {
|
||||
@@ -35,7 +35,7 @@ index e465d8e..18b7317 100644
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
@@ -320,13 +330,17 @@ module.exports = function (webpackEnv) {
|
||||
@@ -320,13 +330,19 @@ module.exports = function (webpackEnv) {
|
||||
.map(ext => `.${ext}`)
|
||||
.filter(ext => useTypeScript || !ext.includes('ts')),
|
||||
alias: {
|
||||
@@ -43,6 +43,8 @@ index e465d8e..18b7317 100644
|
||||
+ "react-dom": path.resolve(path.join(__dirname,'../../react-dom')),
|
||||
+ "@mdi/js": path.resolve(path.join(__dirname,'../../@mdi/js')),
|
||||
+ "@mdi/react": path.resolve(path.join(__dirname,'../../@mdi/react')),
|
||||
+ "@emotion/react": path.resolve(path.join(__dirname,'../../@emotion/react')),
|
||||
+
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
@@ -54,7 +56,7 @@ index e465d8e..18b7317 100644
|
||||
}),
|
||||
...(modules.webpackAliases || {}),
|
||||
},
|
||||
@@ -336,14 +350,14 @@ module.exports = function (webpackEnv) {
|
||||
@@ -336,14 +352,14 @@ module.exports = function (webpackEnv) {
|
||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||
@@ -77,7 +79,7 @@ index e465d8e..18b7317 100644
|
||||
],
|
||||
},
|
||||
module: {
|
||||
@@ -353,7 +367,7 @@ module.exports = function (webpackEnv) {
|
||||
@@ -353,7 +369,7 @@ module.exports = function (webpackEnv) {
|
||||
shouldUseSourceMap && {
|
||||
enforce: 'pre',
|
||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||
@@ -86,7 +88,7 @@ index e465d8e..18b7317 100644
|
||||
loader: require.resolve('source-map-loader'),
|
||||
},
|
||||
{
|
||||
@@ -408,13 +422,13 @@ module.exports = function (webpackEnv) {
|
||||
@@ -408,13 +424,13 @@ module.exports = function (webpackEnv) {
|
||||
},
|
||||
],
|
||||
issuer: {
|
||||
@@ -102,7 +104,7 @@ index e465d8e..18b7317 100644
|
||||
include: paths.appSrc,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
@@ -452,7 +466,7 @@ module.exports = function (webpackEnv) {
|
||||
@@ -452,7 +468,7 @@ module.exports = function (webpackEnv) {
|
||||
plugins: [
|
||||
isEnvDevelopment &&
|
||||
shouldUseReactRefresh &&
|
||||
@@ -111,7 +113,7 @@ index e465d8e..18b7317 100644
|
||||
].filter(Boolean),
|
||||
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||
@@ -460,13 +474,13 @@ module.exports = function (webpackEnv) {
|
||||
@@ -460,13 +476,13 @@ module.exports = function (webpackEnv) {
|
||||
cacheDirectory: true,
|
||||
// See #6846 for context on why cacheCompression is disabled
|
||||
cacheCompression: false,
|
||||
@@ -127,7 +129,7 @@ index e465d8e..18b7317 100644
|
||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
@@ -594,7 +608,7 @@ module.exports = function (webpackEnv) {
|
||||
@@ -594,7 +610,7 @@ module.exports = function (webpackEnv) {
|
||||
// its runtime that would otherwise be processed through "file" loader.
|
||||
// Also exclude `html` and `json` extensions so they get processed
|
||||
// by webpacks internal loaders.
|
||||
|
||||
4
packages/editor/package-lock.json
generated
4
packages/editor/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/editor",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/editor",
|
||||
"version": "1.3.1",
|
||||
"version": "1.4.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
|
||||
@@ -154,7 +154,7 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
const clientY =
|
||||
e instanceof MouseEvent ? e.clientY : e.touches[0].clientY;
|
||||
|
||||
const hitArea = { width: 26, height: 24 };
|
||||
const hitArea = { width: 40, height: 40 };
|
||||
|
||||
const selection = editor.state.selection;
|
||||
const parent = findParentNode((node) => !!node.attrs.textDirection)(
|
||||
|
||||
@@ -21,7 +21,7 @@ import { SearchStorage } from "../../extensions/search-replace";
|
||||
import { FloatingMenuProps } from "./types";
|
||||
import { SearchReplacePopup } from "../popups/search-replace";
|
||||
import { ResponsivePresenter } from "../../components/responsive";
|
||||
import { getToolbarElement } from "../utils/dom";
|
||||
import { getEditorContainer, getToolbarElement } from "../utils/dom";
|
||||
|
||||
export function SearchReplaceFloatingMenu(props: FloatingMenuProps) {
|
||||
const { editor } = props;
|
||||
@@ -34,11 +34,11 @@ export function SearchReplaceFloatingMenu(props: FloatingMenuProps) {
|
||||
isOpen={isSearching}
|
||||
onClose={() => editor.commands.endSearch()}
|
||||
position={{
|
||||
target: getToolbarElement(),
|
||||
target: editor.isEditable ? getToolbarElement() : getEditorContainer(),
|
||||
isTargetAbsolute: true,
|
||||
location: "below",
|
||||
location: editor.isEditable ? "below" : "top",
|
||||
align: "end",
|
||||
yOffset: 5
|
||||
yOffset: editor.isEditable ? 5 : -50
|
||||
}}
|
||||
blocking={false}
|
||||
focusOnRender={false}
|
||||
|
||||
Reference in New Issue
Block a user