mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
mobile: fix tab bugs
This commit is contained in:
committed by
Abdullah Atta
parent
ad41544403
commit
5d2853d002
@@ -40,7 +40,8 @@ import { useAttachmentStore } from "../../stores/use-attachment-store";
|
||||
import {
|
||||
eCloseAttachmentDialog,
|
||||
eCloseSheet,
|
||||
eDBItemUpdate
|
||||
eDBItemUpdate,
|
||||
eOnLoadNote
|
||||
} from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
@@ -53,6 +54,8 @@ import { Notice } from "../ui/notice";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { useTabStore } from "../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../screens/editor/tiptap/utils";
|
||||
|
||||
const Actions = ({
|
||||
attachment,
|
||||
@@ -62,7 +65,7 @@ const Actions = ({
|
||||
}: {
|
||||
attachment: Attachment;
|
||||
setAttachments: (attachments?: VirtualizedGrouping<Attachment>) => void;
|
||||
close: () => void;
|
||||
close?: () => void;
|
||||
fwdRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -103,7 +106,7 @@ const Actions = ({
|
||||
reupload: true,
|
||||
hash: attachment.hash,
|
||||
context: contextId,
|
||||
type: attachment.type
|
||||
type: attachment.mimeType.startsWith("image") ? "image" : "file"
|
||||
});
|
||||
},
|
||||
icon: "upload"
|
||||
@@ -169,10 +172,27 @@ const Actions = ({
|
||||
{
|
||||
name: "Delete",
|
||||
onPress: async () => {
|
||||
const relations = await db.relations.to(attachment, "note").get();
|
||||
await db.attachments.remove(attachment.hash, false);
|
||||
setAttachments();
|
||||
eSendEvent(eDBItemUpdate, attachment.id);
|
||||
close();
|
||||
relations
|
||||
.map((relation) => relation.fromId)
|
||||
.forEach(async (id) => {
|
||||
const tab = useTabStore.getState().getTabForNote(id);
|
||||
if (tab !== undefined) {
|
||||
const isFocused = useTabStore.getState().currentTab === tab;
|
||||
if (isFocused) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: await db.notes.note(id),
|
||||
forced: true
|
||||
});
|
||||
} else {
|
||||
editorController.current.commands.setLoading(true, tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
close?.();
|
||||
},
|
||||
icon: "delete-outline"
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ import {
|
||||
eCloseActionSheet,
|
||||
eCloseVaultDialog,
|
||||
eOnLoadNote,
|
||||
eOpenVaultDialog
|
||||
eOpenVaultDialog,
|
||||
eUpdateNoteInEditor
|
||||
} from "../../../utils/events";
|
||||
import { deleteItems } from "../../../utils/functions";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
@@ -336,7 +337,26 @@ export class VaultDialog extends Component {
|
||||
let verified = await db.user.verifyPassword(this.password);
|
||||
if (!(await db.user.getUser())) verified = true;
|
||||
if (verified) {
|
||||
let noteIds = [];
|
||||
if (this.state.deleteAll) {
|
||||
const vault = await db.vaults.default();
|
||||
const relations = await db.relations.from(vault, "note").get();
|
||||
noteIds = relations.map((item) => item.toId);
|
||||
}
|
||||
|
||||
await db.vault.delete(this.state.deleteAll);
|
||||
|
||||
noteIds.forEach((id) => {
|
||||
eSendEvent(
|
||||
eUpdateNoteInEditor,
|
||||
{
|
||||
id: id,
|
||||
deleted: true
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
eSendEvent("vaultUpdated");
|
||||
this.setState({
|
||||
loading: false
|
||||
@@ -363,7 +383,22 @@ export class VaultDialog extends Component {
|
||||
loading: true
|
||||
});
|
||||
try {
|
||||
const vault = await db.vaults.default();
|
||||
const relations = await db.relations.from(vault, "note").get();
|
||||
const noteIds = relations.map((item) => item.toId);
|
||||
|
||||
await db.vault.clear(this.password);
|
||||
|
||||
noteIds.forEach((id) => {
|
||||
eSendEvent(
|
||||
eUpdateNoteInEditor,
|
||||
{
|
||||
id: id,
|
||||
deleted: true
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
@@ -393,9 +428,9 @@ export class VaultDialog extends Component {
|
||||
} else {
|
||||
await db.vault.add(this.state.note.id);
|
||||
|
||||
// if (this.state.note.id === editorController.current?.note?.id) {
|
||||
// eSendEvent(eClearEditor, );
|
||||
// }
|
||||
console.log("update note event...");
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
|
||||
this.close();
|
||||
ToastManager.show({
|
||||
message: "Note locked successfully",
|
||||
@@ -500,10 +535,7 @@ export class VaultDialog extends Component {
|
||||
}
|
||||
if (this.state.note?.id) {
|
||||
await db.vault.add(this.state.note.id);
|
||||
// TODO
|
||||
// if (this.state.note.id === editorController.current?.note?.id) {
|
||||
// eSendEvent(eClearEditor);
|
||||
// }
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
@@ -533,6 +565,7 @@ export class VaultDialog extends Component {
|
||||
type: "success",
|
||||
context: "global"
|
||||
});
|
||||
eSendEvent(eUpdateNoteInEditor, this.state.note, true);
|
||||
this.close();
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
@@ -16,11 +16,14 @@ 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 { Note } from "@notesnook/core";
|
||||
import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import { useDBItem } from "../../../hooks/use-db-item";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../../screens/editor/tiptap/utils";
|
||||
@@ -38,6 +41,8 @@ type TabItem = {
|
||||
noteId?: string;
|
||||
previewTab?: boolean;
|
||||
locked?: boolean;
|
||||
noteLocked?: boolean;
|
||||
readonly?: boolean;
|
||||
};
|
||||
|
||||
const TabItemComponent = (props: {
|
||||
@@ -46,7 +51,24 @@ const TabItemComponent = (props: {
|
||||
close?: (ctx?: string | undefined) => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const [item] = useDBItem(props.tab.noteId, "note");
|
||||
const [item, update] = useDBItem(props.tab.noteId, "note");
|
||||
|
||||
useEffect(() => {
|
||||
const syncCompletedSubscription = db.eventManager?.subscribe(
|
||||
EVENTS.syncItemMerged,
|
||||
(data: Note) => {
|
||||
if (data.type === "note") {
|
||||
const tabId = useTabStore.getState().getTabForNote(data.id);
|
||||
if (tabId !== undefined && item?.title !== data.title) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return () => {
|
||||
syncCompletedSubscription?.unsubscribe();
|
||||
};
|
||||
}, [update, item]);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
@@ -87,7 +109,18 @@ const TabItemComponent = (props: {
|
||||
gap: 10
|
||||
}}
|
||||
>
|
||||
{props.tab.locked ? <Icon size={SIZE.md} name="lock" /> : null}
|
||||
{props.tab.noteLocked ? (
|
||||
<>
|
||||
{props.tab.locked ? (
|
||||
<Icon size={SIZE.md} name="lock" />
|
||||
) : (
|
||||
<Icon size={SIZE.md} name="lock-open-outline" />
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{props.tab.readonly ? <Icon size={SIZE.md} name="pencil-lock" /> : null}
|
||||
|
||||
<Paragraph
|
||||
color={
|
||||
props.isFocused
|
||||
|
||||
@@ -242,7 +242,6 @@ const ListNoteItem = ({
|
||||
if (noteInternalLinks.length) return;
|
||||
setLoading(true);
|
||||
const blocks = await db.notes.contentBlocks(item.id);
|
||||
|
||||
setNoteInternalLinks(
|
||||
blocks
|
||||
.filter((block) =>
|
||||
@@ -272,7 +271,7 @@ const ListNoteItem = ({
|
||||
listType,
|
||||
noteInternalLinks.length
|
||||
]);
|
||||
|
||||
console.log(noteInternalLinks);
|
||||
const renderBlock = React.useCallback(
|
||||
(block: ContentBlock) => (
|
||||
<ListBlockItem
|
||||
|
||||
@@ -61,7 +61,7 @@ import { useSelectionStore } from "../stores/use-selection-store";
|
||||
import { useTagStore } from "../stores/use-tag-store";
|
||||
import { useUserStore } from "../stores/use-user-store";
|
||||
import Errors from "../utils/errors";
|
||||
import { eOpenLoginDialog } from "../utils/events";
|
||||
import { eOpenLoginDialog, eUpdateNoteInEditor } from "../utils/events";
|
||||
import { deleteItems } from "../utils/functions";
|
||||
import { convertNoteToText } from "../utils/note-to-text";
|
||||
import { sleep } from "../utils/time";
|
||||
@@ -704,10 +704,11 @@ export const useActions = ({
|
||||
}
|
||||
try {
|
||||
await db.vault.add(item.id);
|
||||
const note = await db.notes.note(item.id);
|
||||
const locked = await db.vaults.itemExists(item);
|
||||
if (locked) {
|
||||
close();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
eSendEvent(eUpdateNoteInEditor, item, true);
|
||||
}
|
||||
} catch (e: any) {
|
||||
close();
|
||||
|
||||
@@ -496,7 +496,11 @@ const _TabsHolder = () => {
|
||||
</View>
|
||||
|
||||
<ScopedThemeProvider value="editor">
|
||||
<EditorWrapper key="3" width={widths} dimensions={dimensions} />
|
||||
<EditorWrapper
|
||||
key="3"
|
||||
widths={widths}
|
||||
dimensions={dimensions}
|
||||
/>
|
||||
</ScopedThemeProvider>
|
||||
</FluidTabs>
|
||||
) : null}
|
||||
|
||||
@@ -57,6 +57,7 @@ import { useEditor } from "./tiptap/use-editor";
|
||||
import { useEditorEvents } from "./tiptap/use-editor-events";
|
||||
import { syncTabs, useTabStore } from "./tiptap/use-tab-store";
|
||||
import { editorController, editorState } from "./tiptap/utils";
|
||||
import EditorOverlay from "./loading";
|
||||
|
||||
const style: ViewStyle = {
|
||||
height: "100%",
|
||||
@@ -173,8 +174,6 @@ const Editor = React.memo(
|
||||
autoManageStatusBarEnabled={false}
|
||||
onMessage={onMessage || undefined}
|
||||
/>
|
||||
{/* <EditorOverlay editorId={editorId || ""} editor={editor} /> */}
|
||||
<ReadonlyButton editor={editor} />
|
||||
<LockOverlay />
|
||||
</>
|
||||
);
|
||||
@@ -185,7 +184,6 @@ const Editor = React.memo(
|
||||
|
||||
export default Editor;
|
||||
|
||||
let LOADED = false;
|
||||
const LockOverlay = () => {
|
||||
const tab = useTabStore((state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)
|
||||
@@ -193,27 +191,19 @@ const LockOverlay = () => {
|
||||
const isAppLoading = useSettingStore((state) => state.isAppLoading);
|
||||
const [item] = useDBItem(isAppLoading ? undefined : tab?.noteId, "note");
|
||||
const tabRef = useRef(tab);
|
||||
|
||||
tabRef.current = tab;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAppLoading && !LOADED) {
|
||||
LOADED = true;
|
||||
(async () => {
|
||||
for (const tab of useTabStore.getState().tabs) {
|
||||
const noteId = useTabStore.getState().getTab(tab.id)?.noteId;
|
||||
if (!noteId) continue;
|
||||
const note = await db.notes.note(noteId);
|
||||
const locked = note && (await db.vaults.itemExists(note));
|
||||
if (locked) {
|
||||
useTabStore.getState().updateTab(tab.id, {
|
||||
locked: true
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
for (const tab of useTabStore.getState().tabs) {
|
||||
const noteId = useTabStore.getState().getTab(tab.id)?.noteId;
|
||||
if (!noteId) continue;
|
||||
if (tab.noteLocked) {
|
||||
useTabStore.getState().updateTab(tab.id, {
|
||||
locked: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [isAppLoading]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
@@ -353,43 +343,3 @@ const LockOverlay = () => {
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const ReadonlyButton = ({ editor }: { editor: useEditorType }) => {
|
||||
const readonly = useTabStore(
|
||||
(state) => state.tabs.find((t) => t.id === state.currentTab)?.readonly
|
||||
);
|
||||
|
||||
const keyboard = useKeyboard();
|
||||
const { colors } = useThemeColors();
|
||||
|
||||
const onPress = async () => {
|
||||
const noteId = useTabStore
|
||||
.getState()
|
||||
.getNoteIdForTab(useTabStore.getState().currentTab);
|
||||
if (noteId) {
|
||||
await db.notes.readonly(!editor.note.current.readonly, noteId);
|
||||
editor.note.current[noteId] = await db.notes?.note(noteId);
|
||||
|
||||
useTabStore.getState().updateTab(useTabStore.getState().currentTab, {
|
||||
readonly: editor.note.current[noteId as string]?.readonly
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return readonly && !keyboard.keyboardShown ? (
|
||||
<IconButton
|
||||
name="pencil-lock"
|
||||
type="secondary"
|
||||
onPress={onPress}
|
||||
color={colors.primary.accent}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 60,
|
||||
width: 60,
|
||||
height: 60,
|
||||
right: 12,
|
||||
...getElevationStyle(5)
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
@@ -45,5 +45,6 @@ export const EventTypes = {
|
||||
createInternalLink: "editor-events:create-internal-link",
|
||||
load: "editor-events:load",
|
||||
unlock: "editor-events:unlock",
|
||||
unlockWithBiometrics: "editor-events:unlock-biometrics"
|
||||
unlockWithBiometrics: "editor-events:unlock-biometrics",
|
||||
disableReadonlyMode: "editor-events:disable-readonly-mode"
|
||||
};
|
||||
|
||||
@@ -22,7 +22,11 @@ import { isImage } from "@notesnook/core/dist/utils/filename";
|
||||
import { Platform } from "react-native";
|
||||
import RNFetchBlob from "react-native-blob-util";
|
||||
import DocumentPicker from "react-native-document-picker";
|
||||
import { launchCamera, launchImageLibrary } from "react-native-image-picker";
|
||||
import {
|
||||
ImagePickerResponse,
|
||||
launchCamera,
|
||||
launchImageLibrary
|
||||
} from "react-native-image-picker";
|
||||
import { DatabaseLogger, db } from "../../../common/database";
|
||||
import filesystem from "../../../common/filesystem";
|
||||
import { compressToFile } from "../../../common/filesystem/compress";
|
||||
@@ -213,12 +217,22 @@ const gallery = async (options) => {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{
|
||||
* noteId: string,
|
||||
* tabId: string,
|
||||
* @typedef {{
|
||||
* noteId?: string,
|
||||
* tabId?: string,
|
||||
* type: "image" | "camera" | "file"
|
||||
* reupload: boolean
|
||||
* hash?: string
|
||||
* context?: string
|
||||
* }} ImagePickerOptions
|
||||
*
|
||||
* @param {{
|
||||
* noteId?: string,
|
||||
* tabId?: string,
|
||||
* type: "image" | "camera" | "file"
|
||||
* reupload: boolean
|
||||
* hash?: string
|
||||
* context?: string
|
||||
* }} options
|
||||
* @returns
|
||||
*/
|
||||
@@ -245,7 +259,12 @@ const pick = async (options) => {
|
||||
file(options);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ImagePickerResponse} response
|
||||
* @param {ImagePickerOptions} options
|
||||
* @returns
|
||||
*/
|
||||
const handleImageResponse = async (response, options) => {
|
||||
if (
|
||||
response.didCancel ||
|
||||
@@ -296,6 +315,7 @@ const handleImageResponse = async (response, options) => {
|
||||
if (Platform.OS === "ios") await RNFetchBlob.fs.unlink(uri);
|
||||
console.log("attaching image to note...");
|
||||
if (
|
||||
options.tabId !== undefined &&
|
||||
useTabStore.getState().getNoteIdForTab(options.tabId) === options.noteId
|
||||
) {
|
||||
console.log("attaching image to note...");
|
||||
@@ -315,20 +335,13 @@ const handleImageResponse = async (response, options) => {
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} uri
|
||||
* @param {*} hash
|
||||
* @param {*} type
|
||||
* @param {*} filename
|
||||
/**
|
||||
* @param {{
|
||||
* noteId: string,
|
||||
* tabId: string,
|
||||
* type: "image" | "camera" | "file"
|
||||
* reupload: boolean
|
||||
* hash?: string
|
||||
* }} options
|
||||
* @returns
|
||||
*
|
||||
* @param {string} uri
|
||||
* @param {string} hash
|
||||
* @param {string} type
|
||||
* @param {string} filename
|
||||
* @param {ImagePickerOptions} options
|
||||
* @returns
|
||||
*/
|
||||
export async function attachFile(uri, hash, type, filename, options) {
|
||||
try {
|
||||
|
||||
@@ -154,7 +154,6 @@ export const useEditorEvents = (
|
||||
state.dateFormat,
|
||||
state.timeFormat
|
||||
]);
|
||||
|
||||
const handleBack = useRef<NativeEventSubscription>();
|
||||
const isPremium = useUserStore((state) => state.premium);
|
||||
const { fontScale } = useWindowDimensions();
|
||||
@@ -636,6 +635,25 @@ export const useEditorEvents = (
|
||||
break;
|
||||
}
|
||||
|
||||
case EventTypes.disableReadonlyMode: {
|
||||
const noteId = editorMessage.value;
|
||||
if (noteId) {
|
||||
await db.notes.readonly(false, noteId);
|
||||
editor.note.current[noteId] = await db.notes?.note(noteId);
|
||||
useTabStore
|
||||
.getState()
|
||||
.updateTab(useTabStore.getState().currentTab, {
|
||||
readonly: false
|
||||
});
|
||||
Navigation.queueRoutesForUpdate();
|
||||
ToastManager.show({
|
||||
heading: "Readonly mode disabled.",
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,13 @@ import { EVENTS } from "@notesnook/core/dist/common";
|
||||
import {
|
||||
ContentItem,
|
||||
ContentType,
|
||||
DeletedItem,
|
||||
ItemReference,
|
||||
Note,
|
||||
TrashItem,
|
||||
UnencryptedContentItem,
|
||||
isDeleted
|
||||
isDeleted,
|
||||
isTrashItem
|
||||
} from "@notesnook/core/dist/types";
|
||||
import { useThemeEngineStore } from "@notesnook/theme";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -38,17 +41,16 @@ import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
openVault
|
||||
eUnSubscribeEvent
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import Notifications from "../../../services/notifications";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { useTagStore } from "../../../stores/use-tag-store";
|
||||
import {
|
||||
eClearEditor,
|
||||
eEditorTabFocused,
|
||||
eOnLoadNote
|
||||
eOnLoadNote,
|
||||
eUpdateNoteInEditor
|
||||
} from "../../../utils/events";
|
||||
import { tabBarRef } from "../../../utils/global-refs";
|
||||
import { onNoteCreated } from "../../notes/common";
|
||||
@@ -66,28 +68,6 @@ import {
|
||||
post
|
||||
} from "./utils";
|
||||
|
||||
// Keep a fixed session id, dont' change it when a new note is opened, session id can stay the same always I think once the app is opened. DONE
|
||||
// Editor will save any note content & title is recieved. and dispatch update to relavant tab always.
|
||||
|
||||
// Editor keeps track of what tab is opened and which note is currently focused by keeping a synced zustand store with editor. DONE
|
||||
// the useEditor hook can recieve save messages for different notes at a time. DONE
|
||||
// When a note is created, the useEditor hook must immediately notify the editor with the note id and set the note id in the editor tabs store
|
||||
// so further changes will go into that note. DONE
|
||||
// Events sent to editor have the tab id value added to ensure the correct tab will recieve and return events only. DONE
|
||||
// The useEditorEvents hook can manage events from different tabs at the same time as long as the attached session id matches. DONE
|
||||
// useEditor hook will keep historySessionId for different notes instead of a single note. DONE
|
||||
//
|
||||
// LIST OF CASES TO VERIFY WITH TABS OPENING & CLOSING
|
||||
// 1. SWITCHING TAB CLOSES THE SHEET. DONE
|
||||
// 2. Closing the tab does proper cleanup if it's the last tab and is not empty. DONE
|
||||
// 3. Swiping left only focuses editor if current tab is empty. DONE
|
||||
// 4. Pressing + button will open a new tab for new note if an empty tab does not exist.
|
||||
// 5. Notes will always open in the preview tab.
|
||||
// 6. If a note is edited, the tab will become persisted.
|
||||
// 7. If note is already opened in a tab, we focus that tab.
|
||||
// 8. If app is killed, restore the note in background.
|
||||
// 9. During realtimes sync, tabs not focused will be updated so if focused, they have the latest and updated content loaded.
|
||||
|
||||
type NoteWithContent = Note & {
|
||||
content?: NoteContent<false>;
|
||||
};
|
||||
@@ -219,7 +199,8 @@ export const useEditor = (
|
||||
resetContent && (await commands.clearTags(tabId));
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
noteId: undefined,
|
||||
locked: false
|
||||
locked: false,
|
||||
noteLocked: false
|
||||
});
|
||||
},
|
||||
[commands, editorSessionHistory, postMessage]
|
||||
@@ -431,7 +412,8 @@ export const useEditor = (
|
||||
if (typeof tabId === "number") {
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
readonly: event.item.readonly || readonly,
|
||||
locked: noteIsLocked
|
||||
locked: noteIsLocked,
|
||||
noteLocked: noteIsLocked
|
||||
});
|
||||
useTabStore.getState().focusTab(tabId);
|
||||
setTimeout(() => {
|
||||
@@ -448,7 +430,8 @@ export const useEditor = (
|
||||
// Otherwise we focus the preview tab or create one to open the note in.
|
||||
useTabStore.getState().focusPreviewTab(event.item.id, {
|
||||
readonly: event.item.readonly || readonly,
|
||||
locked: noteIsLocked
|
||||
locked: noteIsLocked,
|
||||
noteLocked: noteIsLocked
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -546,48 +529,103 @@ export const useEditor = (
|
||||
]
|
||||
);
|
||||
|
||||
const lockNoteWithVault = useCallback((note: Note) => {
|
||||
eSendEvent(eClearEditor);
|
||||
openVault({
|
||||
item: note,
|
||||
novault: true,
|
||||
locked: true,
|
||||
goToEditor: true,
|
||||
title: "Open note",
|
||||
description: "Unlock note to open it in editor."
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onSyncComplete = useCallback(
|
||||
async (data: Note | ContentItem) => {
|
||||
if (SettingsService.get().disableRealtimeSync) return;
|
||||
async (
|
||||
data: Note | ContentItem | TrashItem | DeletedItem,
|
||||
isLocal?: boolean
|
||||
) => {
|
||||
console.log("Local changes in editor", isLocal, data?.id);
|
||||
if (SettingsService.get().disableRealtimeSync && !isLocal) return;
|
||||
if (!data) return;
|
||||
const noteId = data.type === "tiptap" ? data.noteId : data.id;
|
||||
|
||||
if (isDeleted(data) || isTrashItem(data)) {
|
||||
const tabId = useTabStore.getState().getTabForNote(data.id);
|
||||
if (tabId !== undefined) {
|
||||
useTabStore.getState().removeTab(tabId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const noteId =
|
||||
(data as ContentItem).type === "tiptap"
|
||||
? (data as ContentItem).noteId
|
||||
: data.id;
|
||||
|
||||
if (!useTabStore.getState().hasTabForNote(noteId)) return;
|
||||
const tabId = useTabStore.getState().getTabForNote(noteId) as number;
|
||||
|
||||
const tabId = useTabStore.getState().getTabForNote(noteId);
|
||||
const isContentEncrypted =
|
||||
typeof (data as ContentItem)?.data === "object";
|
||||
const tab = useTabStore.getState().getTab(tabId);
|
||||
|
||||
const note = await db.notes?.note(noteId);
|
||||
|
||||
if (lastContentChangeTime.current[noteId] >= (data as Note).dateEdited)
|
||||
return;
|
||||
const note = data.type === "note" ? data : await db.notes?.note(noteId);
|
||||
|
||||
lock.current = true;
|
||||
|
||||
if (data.type === "tiptap" && note) {
|
||||
// Handle this case where note was locked on another device and synced.
|
||||
const locked = await db.vaults.itemExists(
|
||||
currentNotes.current[note.id] as ItemReference
|
||||
);
|
||||
if (!locked && isContentEncrypted) {
|
||||
lockNoteWithVault(note);
|
||||
} else if (locked && isEncryptedContent(data)) {
|
||||
// Handle this case where note was locked on another device and synced.
|
||||
const locked = await db.vaults.itemExists(
|
||||
currentNotes.current[noteId] as ItemReference
|
||||
);
|
||||
|
||||
if (note) {
|
||||
if (!locked && tab?.noteLocked) {
|
||||
// Note lock removed.
|
||||
if (tab.locked) {
|
||||
if (useTabStore.getState().currentTab === tabId) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note,
|
||||
forced: true
|
||||
});
|
||||
} else {
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
locked: false,
|
||||
noteLocked: false
|
||||
});
|
||||
commands.setLoading(true, tabId);
|
||||
}
|
||||
}
|
||||
} else if (!tab?.noteLocked && locked) {
|
||||
// Note lock added.
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
locked: true,
|
||||
noteLocked: true
|
||||
});
|
||||
if (useTabStore.getState().currentTab !== tabId) {
|
||||
commands.clearContent(tabId);
|
||||
commands.setLoading(true, tabId);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentNotes.current[noteId]?.title !== note.title) {
|
||||
postMessage(EditorEvents.title, note.title, tabId);
|
||||
}
|
||||
commands.setTags(note);
|
||||
if (currentNotes.current[noteId]?.dateEdited !== note.dateEdited) {
|
||||
commands.setStatus(
|
||||
getFormattedDate(note.dateEdited, "date-time"),
|
||||
"Saved",
|
||||
tabId as number
|
||||
);
|
||||
}
|
||||
|
||||
console.log("readonly state changed...", note.readonly);
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
readonly: note.readonly
|
||||
});
|
||||
}
|
||||
|
||||
if (data.type === "tiptap" && note && !isLocal) {
|
||||
if (lastContentChangeTime.current[noteId] >= data.dateEdited) return;
|
||||
|
||||
if (locked && isEncryptedContent(data)) {
|
||||
const decryptedContent = await db.vault?.decryptContent(data, noteId);
|
||||
if (!decryptedContent) {
|
||||
lockNoteWithVault(note);
|
||||
useTabStore.getState().updateTab(tabId, {
|
||||
locked: true,
|
||||
noteLocked: true
|
||||
});
|
||||
if (useTabStore.getState().currentTab !== tabId) {
|
||||
commands.clearContent(tabId);
|
||||
commands.setLoading(true, tabId);
|
||||
}
|
||||
} else {
|
||||
await postMessage(
|
||||
EditorEvents.updatehtml,
|
||||
@@ -605,30 +643,20 @@ export const useEditor = (
|
||||
currentContents.current[note.id] = data as UnencryptedContentItem;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!note) return;
|
||||
postMessage(EditorEvents.title, note.title, tabId);
|
||||
commands.setTags(note);
|
||||
commands.setStatus(
|
||||
getFormattedDate(note.dateEdited, "date-time"),
|
||||
"Saved",
|
||||
tabId as number
|
||||
);
|
||||
}
|
||||
lock.current = false;
|
||||
},
|
||||
[lockNoteWithVault, postMessage, commands]
|
||||
[postMessage, commands]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const syncCompletedSubscription = db.eventManager?.subscribe(
|
||||
EVENTS.syncItemMerged,
|
||||
onSyncComplete
|
||||
);
|
||||
eSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
const subs = [
|
||||
db.eventManager.subscribe(EVENTS.syncItemMerged, onSyncComplete),
|
||||
eSubscribeEvent(eOnLoadNote + editorId, loadNote),
|
||||
eSubscribeEvent(eUpdateNoteInEditor, onSyncComplete)
|
||||
];
|
||||
return () => {
|
||||
syncCompletedSubscription?.unsubscribe();
|
||||
eUnSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
subs.forEach((sub) => sub?.unsubscribe());
|
||||
};
|
||||
}, [editorId, loadNote, onSyncComplete]);
|
||||
|
||||
|
||||
@@ -18,9 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import create from "zustand";
|
||||
import { persist, StateStorage } from "zustand/middleware";
|
||||
import { editorController } from "./utils";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import { db } from "../../../common/database";
|
||||
import { editorController } from "./utils";
|
||||
|
||||
class History {
|
||||
history: number[];
|
||||
@@ -76,6 +75,7 @@ export type TabItem = {
|
||||
previewTab?: boolean;
|
||||
readonly?: boolean;
|
||||
locked?: boolean;
|
||||
noteLocked?: boolean;
|
||||
};
|
||||
|
||||
const history = new History();
|
||||
|
||||
@@ -76,8 +76,8 @@ export const eUnSubscribeEvent = <T = unknown>(
|
||||
eventManager.unsubscribe(eventName, action);
|
||||
};
|
||||
|
||||
export const eSendEvent = (eventName: string, data?: unknown) => {
|
||||
eventManager.publish(eventName, data);
|
||||
export const eSendEvent = (eventName: string, ...args: any[]) => {
|
||||
eventManager.publish(eventName, ...args);
|
||||
};
|
||||
|
||||
export const openVault = (data: Partial<Vault>) => {
|
||||
|
||||
@@ -171,3 +171,4 @@ export const eUnlockNote = "616";
|
||||
export const eOnChangeFluidTab = "617";
|
||||
export const eUnlockWithBiometrics = "618";
|
||||
export const eUnlockWithPassword = "619";
|
||||
export const eUpdateNoteInEditor = "620";
|
||||
|
||||
@@ -25,7 +25,7 @@ import Navigation from "../services/navigation";
|
||||
import { useMenuStore } from "../stores/use-menu-store";
|
||||
import { useRelationStore } from "../stores/use-relation-store";
|
||||
import { useSelectionStore } from "../stores/use-selection-store";
|
||||
import { eClearEditor, eOnNotebookUpdated } from "./events";
|
||||
import { eOnNotebookUpdated, eUpdateNoteInEditor } from "./events";
|
||||
import { getParentNotebookId } from "./notebooks";
|
||||
|
||||
function confirmDeleteAllNotes(items, type, context) {
|
||||
@@ -92,8 +92,17 @@ export const deleteItems = async (items, type, context) => {
|
||||
continue;
|
||||
}
|
||||
await db.notes.moveToTrash(id);
|
||||
|
||||
eSendEvent(
|
||||
eUpdateNoteInEditor,
|
||||
{
|
||||
type: "trash",
|
||||
id: id,
|
||||
itemType: "note"
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
eSendEvent(eClearEditor);
|
||||
} else if (type === "notebook") {
|
||||
const result = await confirmDeleteAllNotes(ids, "notebook", context);
|
||||
if (!result.delete) return;
|
||||
|
||||
@@ -964,4 +964,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 2b8b28a341b202bf3ca5f231b75bb05893486ed8
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
COCOAPODS: 1.14.2
|
||||
|
||||
111
apps/mobile/package-lock.json
generated
111
apps/mobile/package-lock.json
generated
@@ -7177,7 +7177,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/prop-types": {
|
||||
"version": "15.7.11",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/q": {
|
||||
@@ -7197,7 +7197,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/react": {
|
||||
"version": "18.2.39",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -7228,7 +7228,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/scheduler": {
|
||||
"version": "0.16.8",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/semver": {
|
||||
@@ -12086,7 +12086,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/immer": {
|
||||
"version": "9.0.21",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -22490,6 +22490,7 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor/node_modules/json-parse-even-better-errors": {
|
||||
@@ -22545,6 +22546,7 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
@@ -23066,6 +23068,7 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/react": {
|
||||
"version": "18.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -23084,6 +23087,7 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
@@ -23203,6 +23207,7 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -30919,6 +30924,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -30932,6 +30938,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31078,6 +31085,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-proposal-private-property-in-object": {
|
||||
"version": "7.21.0-placeholder-for-preset-env.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -31088,6 +31096,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-proposal-unicode-property-regex": {
|
||||
"version": "7.18.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
|
||||
@@ -31133,6 +31142,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-class-static-block": {
|
||||
"version": "7.14.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
@@ -31169,6 +31179,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-export-namespace-from": {
|
||||
"version": "7.8.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.8.3"
|
||||
@@ -31192,6 +31203,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-assertions": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -31205,6 +31217,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-attributes": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -31218,6 +31231,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-import-meta": {
|
||||
"version": "7.10.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.10.4"
|
||||
@@ -31228,6 +31242,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-json-strings": {
|
||||
"version": "7.8.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.8.0"
|
||||
@@ -31251,6 +31266,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-logical-assignment-operators": {
|
||||
"version": "7.10.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.10.4"
|
||||
@@ -31311,6 +31327,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-private-property-in-object": {
|
||||
"version": "7.14.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
@@ -31324,6 +31341,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-top-level-await": {
|
||||
"version": "7.14.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
@@ -31350,6 +31368,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-unicode-sets-regex": {
|
||||
"version": "7.18.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
|
||||
@@ -31377,6 +31396,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-async-generator-functions": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
@@ -31434,6 +31454,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-properties": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.5",
|
||||
@@ -31448,6 +31469,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-class-static-block": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.5",
|
||||
@@ -31511,6 +31533,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dotall-regex": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
@@ -31525,6 +31548,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-duplicate-keys": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -31538,6 +31562,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-dynamic-import": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31566,6 +31591,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-export-namespace-from": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31622,6 +31648,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-json-strings": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31649,6 +31676,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-logical-assignment-operators": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31676,6 +31704,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-amd": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
@@ -31705,6 +31734,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-systemjs": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
@@ -31721,6 +31751,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-umd": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
@@ -31749,6 +31780,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-new-target": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -31762,6 +31794,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31776,6 +31809,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-numeric-separator": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31803,6 +31837,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.5",
|
||||
@@ -31834,6 +31869,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-catch-binding": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31848,6 +31884,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-chaining": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -31876,6 +31913,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-methods": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.5",
|
||||
@@ -31890,6 +31928,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-property-in-object": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
@@ -31989,6 +32028,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-reserved-words": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -32080,6 +32120,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-typeof-symbol": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -32109,6 +32150,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-escapes": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -32122,6 +32164,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-property-regex": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
@@ -32150,6 +32193,7 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-unicode-sets-regex": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
@@ -32164,6 +32208,7 @@
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.5",
|
||||
@@ -32256,6 +32301,7 @@
|
||||
},
|
||||
"node_modules/@babel/preset-env/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
@@ -32278,6 +32324,7 @@
|
||||
},
|
||||
"node_modules/@babel/preset-modules": {
|
||||
"version": "0.1.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.0.0",
|
||||
@@ -34893,6 +34940,7 @@
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.40.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "*",
|
||||
@@ -34901,6 +34949,7 @@
|
||||
},
|
||||
"node_modules/@types/eslint-scope": {
|
||||
"version": "3.7.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint": "*",
|
||||
@@ -34909,6 +34958,7 @@
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.1",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/graceful-fs": {
|
||||
@@ -35357,6 +35407,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
@@ -35365,18 +35416,22 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/floating-point-hex-parser": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-api-error": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
|
||||
@@ -35386,10 +35441,12 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35400,6 +35457,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@xtuc/ieee754": "^1.2.0"
|
||||
@@ -35407,6 +35465,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/leb128": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@xtuc/long": "4.2.2"
|
||||
@@ -35414,10 +35473,12 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/utf8": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35432,6 +35493,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35443,6 +35505,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35453,6 +35516,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35465,6 +35529,7 @@
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
@@ -35522,10 +35587,12 @@
|
||||
},
|
||||
"node_modules/@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@xtuc/long": {
|
||||
"version": "4.2.2",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@yarnpkg/lockfile": {
|
||||
@@ -35581,6 +35648,7 @@
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.9.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
@@ -36682,6 +36750,7 @@
|
||||
},
|
||||
"node_modules/chrome-trace-event": {
|
||||
"version": "1.0.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
@@ -37743,6 +37812,7 @@
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.15.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
@@ -37855,6 +37925,7 @@
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.3.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
@@ -38185,6 +38256,7 @@
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
@@ -38196,6 +38268,7 @@
|
||||
},
|
||||
"node_modules/eslint-scope/node_modules/estraverse": {
|
||||
"version": "4.3.0",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
@@ -38381,6 +38454,7 @@
|
||||
},
|
||||
"node_modules/esrecurse": {
|
||||
"version": "4.3.0",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"estraverse": "^5.2.0"
|
||||
@@ -38391,6 +38465,7 @@
|
||||
},
|
||||
"node_modules/estraverse": {
|
||||
"version": "5.3.0",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
@@ -38398,6 +38473,7 @@
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -39450,6 +39526,7 @@
|
||||
},
|
||||
"node_modules/glob-to-regexp": {
|
||||
"version": "0.4.1",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/global": {
|
||||
@@ -41687,6 +41764,7 @@
|
||||
},
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
@@ -41952,6 +42030,7 @@
|
||||
},
|
||||
"node_modules/loader-runner": {
|
||||
"version": "4.3.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.11.5"
|
||||
@@ -44574,6 +44653,7 @@
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
@@ -45350,6 +45430,7 @@
|
||||
},
|
||||
"node_modules/react-test-renderer": {
|
||||
"version": "18.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-is": "^18.2.0",
|
||||
@@ -45362,10 +45443,12 @@
|
||||
},
|
||||
"node_modules/react-test-renderer/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-test-renderer/node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -46200,6 +46283,7 @@
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.1",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -47254,6 +47338,7 @@
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.3.9",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
@@ -47286,6 +47371,7 @@
|
||||
},
|
||||
"node_modules/terser-webpack-plugin/node_modules/jest-worker": {
|
||||
"version": "27.5.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
@@ -47298,6 +47384,7 @@
|
||||
},
|
||||
"node_modules/terser-webpack-plugin/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
@@ -47711,19 +47798,6 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.8.4",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ua-parser-js": {
|
||||
"version": "0.7.35",
|
||||
"funding": [
|
||||
@@ -48052,6 +48126,7 @@
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -48074,6 +48149,7 @@
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.88.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
@@ -48188,6 +48264,7 @@
|
||||
},
|
||||
"node_modules/webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
|
||||
1
packages/editor-mobile/package-lock.json
generated
1
packages/editor-mobile/package-lock.json
generated
@@ -69,6 +69,7 @@
|
||||
"detect-indent": "^7.0.0",
|
||||
"entities": "^4.5.0",
|
||||
"katex": "0.16.4",
|
||||
"linkifyjs": "^4.1.3",
|
||||
"nanoid": "^4.0.1",
|
||||
"prism-themes": "^1.9.0",
|
||||
"prosemirror-codemark": "^0.4.2",
|
||||
|
||||
@@ -130,9 +130,9 @@ const Tiptap = ({
|
||||
});
|
||||
},
|
||||
element: getContentDiv(),
|
||||
editable: !settings.readonly,
|
||||
editable: !tab.readonly,
|
||||
editorProps: {
|
||||
editable: () => !settings.readonly
|
||||
editable: () => !tab.readonly
|
||||
},
|
||||
content: globalThis.editorControllers[tab.id]?.content?.current,
|
||||
isMobile: true,
|
||||
@@ -168,7 +168,7 @@ const Tiptap = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
getContentDiv,
|
||||
settings.readonly,
|
||||
tab.readonly,
|
||||
settings.doubleSpacedLines,
|
||||
settings.corsProxy,
|
||||
settings.dateFormat,
|
||||
@@ -386,22 +386,22 @@ const Tiptap = ({
|
||||
>
|
||||
{settings.noHeader || tab.locked ? null : (
|
||||
<>
|
||||
<Tags settings={settings} />
|
||||
<Tags settings={settings} loading={controller.loading} />
|
||||
<Title
|
||||
titlePlaceholder={controller.titlePlaceholder}
|
||||
readonly={settings.readonly}
|
||||
controller={controllerRef}
|
||||
title={controller.title}
|
||||
fontFamily={settings.fontFamily}
|
||||
dateFormat={settings.dateFormat}
|
||||
timeFormat={settings.timeFormat}
|
||||
loading={controller.loading}
|
||||
/>
|
||||
|
||||
{controller.loading ? null : (
|
||||
<>
|
||||
<Title
|
||||
titlePlaceholder={controller.titlePlaceholder}
|
||||
readonly={settings.readonly}
|
||||
controller={controllerRef}
|
||||
title={controller.title}
|
||||
fontFamily={settings.fontFamily}
|
||||
dateFormat={settings.dateFormat}
|
||||
timeFormat={settings.timeFormat}
|
||||
/>
|
||||
<StatusBar container={containerRef} />
|
||||
</>
|
||||
)}
|
||||
<StatusBar
|
||||
container={containerRef}
|
||||
loading={controller.loading}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import DotsHorizontalIcon from "mdi-react/DotsHorizontalIcon";
|
||||
import DotsVerticalIcon from "mdi-react/DotsVerticalIcon";
|
||||
import FullscreenIcon from "mdi-react/FullscreenIcon";
|
||||
import MagnifyIcon from "mdi-react/MagnifyIcon";
|
||||
import PencilLockIcon from "mdi-react/PencilLockIcon";
|
||||
import TableOfContentsIcon from "mdi-react/TableOfContentsIcon";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { useSafeArea } from "../hooks/useSafeArea";
|
||||
@@ -56,9 +57,11 @@ const Button = ({
|
||||
children,
|
||||
style,
|
||||
preventDefault = true,
|
||||
fwdRef
|
||||
fwdRef,
|
||||
onClick
|
||||
}: {
|
||||
onPress: () => void;
|
||||
onPress?: () => void;
|
||||
onClick?: (event: any) => void;
|
||||
children: React.ReactNode;
|
||||
style: React.CSSProperties;
|
||||
preventDefault?: boolean;
|
||||
@@ -71,7 +74,8 @@ const Button = ({
|
||||
style={style}
|
||||
onMouseDown={(e) => {
|
||||
if (preventDefault) e.preventDefault();
|
||||
onPress();
|
||||
onPress?.();
|
||||
onClick?.(e);
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@@ -219,6 +223,41 @@ function Header({
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
{tab.readonly ? (
|
||||
<Button
|
||||
onPress={() => {
|
||||
post(
|
||||
"editor-events:disable-readonly-mode",
|
||||
useTabStore
|
||||
.getState()
|
||||
.getNoteIdForTab(useTabStore.getState().currentTab)
|
||||
);
|
||||
}}
|
||||
fwdRef={btnRef}
|
||||
preventDefault={false}
|
||||
style={{
|
||||
borderWidth: 0,
|
||||
borderRadius: 100,
|
||||
color: "var(--nn_primary_accent)",
|
||||
marginRight: 12,
|
||||
width: 39,
|
||||
height: 39,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
<PencilLockIcon
|
||||
size={25 * settings.fontScale}
|
||||
style={{
|
||||
position: "absolute"
|
||||
}}
|
||||
color="var(--nn_primary_accent)"
|
||||
/>
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
<Button
|
||||
onPress={() => {
|
||||
post(EventTypes.showTabs, undefined, tab.id, tab.noteId);
|
||||
@@ -263,10 +302,10 @@ function Header({
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
fwdRef={btnRef}
|
||||
onPress={() => {
|
||||
setOpen(!isOpen);
|
||||
}}
|
||||
fwdRef={btnRef}
|
||||
preventDefault={false}
|
||||
style={{
|
||||
borderWidth: 0,
|
||||
@@ -293,7 +332,6 @@ function Header({
|
||||
<ControlledMenu
|
||||
align="end"
|
||||
anchorRef={btnRef}
|
||||
transition
|
||||
state={isOpen ? "open" : "closed"}
|
||||
menuClassName={menuClassName}
|
||||
onClose={() => {
|
||||
|
||||
@@ -21,7 +21,13 @@ import React, { RefObject, useEffect, useRef, useState } from "react";
|
||||
import { getTotalWords, Editor } from "@notesnook/editor";
|
||||
import { useTabContext } from "../hooks/useTabStore";
|
||||
|
||||
function StatusBar({ container }: { container: RefObject<HTMLDivElement> }) {
|
||||
function StatusBar({
|
||||
container,
|
||||
loading
|
||||
}: {
|
||||
container: RefObject<HTMLDivElement>;
|
||||
loading?: boolean;
|
||||
}) {
|
||||
const [status, setStatus] = useState({
|
||||
date: "",
|
||||
saved: ""
|
||||
@@ -106,7 +112,7 @@ function StatusBar({ container }: { container: RefObject<HTMLDivElement> }) {
|
||||
<div
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
display: "flex",
|
||||
display: loading ? "none" : "flex",
|
||||
paddingRight: 12,
|
||||
paddingLeft: 12,
|
||||
position: sticky ? "sticky" : "relative",
|
||||
@@ -126,4 +132,7 @@ function StatusBar({ container }: { container: RefObject<HTMLDivElement> }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(StatusBar, () => true);
|
||||
export default React.memo(
|
||||
StatusBar,
|
||||
(prev, next) => prev.loading === next.loading
|
||||
);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@keyframes menuShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
@@ -51,10 +50,10 @@
|
||||
z-index: 999;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
padding: 6px;
|
||||
padding: 0px;
|
||||
font-family: sans-serif;
|
||||
font-size: 0.95em;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid var(--nn_primary_border);
|
||||
box-shadow: 1px 1px 20px 1px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 6px;
|
||||
background-color: var(--nn_secondary_background);
|
||||
@@ -73,12 +72,11 @@
|
||||
|
||||
.menuItem {
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
padding: 0.375rem 0.625rem;
|
||||
border-radius: 0;
|
||||
padding: 1rem 0.6rem !important;
|
||||
color: var(--nn_primary_paragraph);
|
||||
font-family: 'Open Sans';
|
||||
font-family: "Open Sans";
|
||||
padding: 12px 6px;
|
||||
|
||||
}
|
||||
|
||||
.menuItemHover {
|
||||
@@ -102,5 +100,4 @@
|
||||
height: 1px;
|
||||
margin: 0.1rem 0.1rem;
|
||||
background-color: var(--nn_primary_border);
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import { EventTypes, Settings } from "../utils";
|
||||
import styles from "./styles.module.css";
|
||||
import { useTabContext } from "../hooks/useTabStore";
|
||||
|
||||
function Tags(props: { settings: Settings }): JSX.Element {
|
||||
function Tags(props: { settings: Settings; loading?: boolean }): JSX.Element {
|
||||
const [tags, setTags] = useState<
|
||||
{ title: string; alias: string; id: string; type: "tag" }[]
|
||||
>([]);
|
||||
@@ -56,7 +56,8 @@ function Tags(props: { settings: Settings }): JSX.Element {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
overflowX: "scroll",
|
||||
minHeight: "40px"
|
||||
minHeight: "40px",
|
||||
opacity: props.loading ? 0 : 1
|
||||
}}
|
||||
>
|
||||
<button
|
||||
@@ -135,6 +136,10 @@ function Tags(props: { settings: Settings }): JSX.Element {
|
||||
}
|
||||
|
||||
export default React.memo(Tags, (prev, next) => {
|
||||
if (prev.settings.fontScale !== next.settings.fontScale) return false;
|
||||
if (
|
||||
prev.settings.fontScale !== next.settings.fontScale ||
|
||||
prev.loading !== next.loading
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -30,7 +30,8 @@ function Title({
|
||||
readonly,
|
||||
fontFamily,
|
||||
dateFormat,
|
||||
timeFormat
|
||||
timeFormat,
|
||||
loading
|
||||
}: {
|
||||
controller: RefObject<EditorController>;
|
||||
title: string;
|
||||
@@ -39,6 +40,7 @@ function Title({
|
||||
fontFamily: string;
|
||||
dateFormat: string;
|
||||
timeFormat: string;
|
||||
loading?: boolean;
|
||||
}) {
|
||||
const tab = useTabContext();
|
||||
const titleRef = useRef<HTMLTextAreaElement>(null);
|
||||
@@ -95,7 +97,8 @@ function Title({
|
||||
pointerEvents: "none",
|
||||
overflowWrap: "anywhere",
|
||||
paddingTop: 3,
|
||||
whiteSpace: "break-spaces"
|
||||
whiteSpace: "break-spaces",
|
||||
display: loading ? "none" : undefined
|
||||
}}
|
||||
/>
|
||||
<textarea
|
||||
@@ -122,7 +125,8 @@ function Title({
|
||||
borderRadius: 0,
|
||||
overflow: "hidden",
|
||||
overflowX: "hidden",
|
||||
overflowY: "hidden"
|
||||
overflowY: "hidden",
|
||||
display: loading ? "none" : undefined
|
||||
}}
|
||||
maxLength={1000}
|
||||
onInput={() => {
|
||||
@@ -160,7 +164,8 @@ export default React.memo(Title, (prev, next) => {
|
||||
prev.title !== next.title ||
|
||||
prev.titlePlaceholder !== next.titlePlaceholder ||
|
||||
prev.readonly !== next.readonly ||
|
||||
prev.fontFamily !== next.fontFamily
|
||||
prev.fontFamily !== next.fontFamily ||
|
||||
prev.loading !== next.loading
|
||||
)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ export type TabItem = {
|
||||
previewTab?: boolean;
|
||||
readonly?: boolean;
|
||||
locked?: boolean;
|
||||
noteLocked?: boolean;
|
||||
};
|
||||
|
||||
type NoteState = {
|
||||
|
||||
@@ -188,7 +188,8 @@ export const EventTypes = {
|
||||
createInternalLink: "editor-events:create-internal-link",
|
||||
load: "editor-events:load",
|
||||
unlock: "editor-events:unlock",
|
||||
unlockWithBiometrics: "editor-events:unlock-biometrics"
|
||||
unlockWithBiometrics: "editor-events:unlock-biometrics",
|
||||
disableReadonlyMode: "editor-events:disable-readonly-mode"
|
||||
} as const;
|
||||
|
||||
export function randId(prefix: string) {
|
||||
|
||||
Reference in New Issue
Block a user