mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-05-18 05:05:36 +02:00
Merge branch 'master' into beta
This commit is contained in:
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./overrides";
|
||||
import { app, BrowserWindow, nativeTheme, shell } from "electron";
|
||||
import { app, BrowserWindow, nativeTheme, shell, dialog } from "electron";
|
||||
import { isDevelopment } from "./utils";
|
||||
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
|
||||
import { configureAutoUpdater } from "./utils/autoupdater";
|
||||
@@ -182,6 +182,17 @@ async function createWindow() {
|
||||
app.once("ready", async () => {
|
||||
console.info("App ready. Opening window.");
|
||||
|
||||
if (app.runningUnderARM64Translation) {
|
||||
console.log("App is running under ARM64 translation");
|
||||
dialog.showMessageBoxSync({
|
||||
message:
|
||||
"Notesnook detected that it is running under ARM64 translation. For the best performance, please download the ARM64 build of Notesnook from our website.",
|
||||
type: "warning",
|
||||
buttons: ["Okay"],
|
||||
title: "Degraded Performance Warning"
|
||||
});
|
||||
}
|
||||
|
||||
if (config.customDns) enableCustomDns();
|
||||
else disableCustomDns();
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ export type Settings = {
|
||||
fontScale: number;
|
||||
markdownShortcuts: boolean;
|
||||
features: Record<any, any>;
|
||||
loggedIn: boolean;
|
||||
};
|
||||
|
||||
export type EditorProps = {
|
||||
|
||||
@@ -165,6 +165,7 @@ export const useEditorEvents = (
|
||||
state.timeFormat
|
||||
]);
|
||||
const handleBack = useRef<NativeEventSubscription>();
|
||||
const loggedIn = useUserStore((state) => !!state.user);
|
||||
const { fontScale } = useWindowDimensions();
|
||||
|
||||
const doubleSpacedLines = useSettingStore(
|
||||
@@ -224,7 +225,8 @@ export const useEditorEvents = (
|
||||
timeFormat: db.settings?.getTimeFormat(),
|
||||
fontScale,
|
||||
markdownShortcuts,
|
||||
features
|
||||
features,
|
||||
loggedIn
|
||||
});
|
||||
}, [
|
||||
fullscreen,
|
||||
@@ -242,7 +244,8 @@ export const useEditorEvents = (
|
||||
timeFormat,
|
||||
loading,
|
||||
fontScale,
|
||||
markdownShortcuts
|
||||
markdownShortcuts,
|
||||
loggedIn
|
||||
]);
|
||||
|
||||
const onBackPress = useCallback(async () => {
|
||||
@@ -556,9 +559,17 @@ export const useEditorEvents = (
|
||||
if (editor.state.current?.isFocused) {
|
||||
editor.state.current.isFocused = true;
|
||||
}
|
||||
PaywallSheet.present(
|
||||
await isFeatureAvailable(editorMessage.value.feature)
|
||||
);
|
||||
if (editorMessage.value.feature === "insertAttachment") {
|
||||
ToastManager.show({
|
||||
type: "info",
|
||||
message: strings.loginRequired()
|
||||
});
|
||||
} else {
|
||||
PaywallSheet.present(
|
||||
await isFeatureAvailable(editorMessage.value.feature)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
case EditorEvents.monograph:
|
||||
publishNote();
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
useStore as useAppStore,
|
||||
store as appstore
|
||||
} from "../../stores/app-store";
|
||||
import { useStore as useUserStore } from "../../stores/user-store";
|
||||
import { useStore as useSearchStore } from "../../stores/search-store";
|
||||
import { AppEventManager, AppEvents } from "../../common/app-events";
|
||||
import { FlexScrollContainer } from "../scroll-container";
|
||||
@@ -77,6 +78,7 @@ import { Pane, SplitPane } from "../split-pane";
|
||||
import { TITLE_BAR_HEIGHT } from "../title-bar";
|
||||
import { isMobile } from "../../hooks/use-mobile";
|
||||
import { isTablet } from "../../hooks/use-tablet";
|
||||
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||
|
||||
const PDFPreview = React.lazy(() => import("../pdf-preview"));
|
||||
|
||||
@@ -604,6 +606,15 @@ export function Editor(props: EditorProps) {
|
||||
}
|
||||
}}
|
||||
onInsertAttachment={async (type) => {
|
||||
if (!useUserStore.getState().isLoggedIn) {
|
||||
ConfirmDialog.show({
|
||||
title: strings.notLoggedIn(),
|
||||
message: strings.loginToUploadAttachments(),
|
||||
positiveButtonText: strings.okay()
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const mime = type === "file" ? "*/*" : "image/*";
|
||||
const attachments = await insertAttachments(mime);
|
||||
const editor = useEditorManager.getState().getEditor(id)?.editor;
|
||||
|
||||
@@ -51,6 +51,7 @@ import {
|
||||
import { IEditor, MAX_AUTO_SAVEABLE_WORDS } from "./types";
|
||||
import { useEditorConfig, useToolbarConfig, useEditorManager } from "./manager";
|
||||
import { useStore as useSettingsStore } from "../../stores/setting-store";
|
||||
import { useStore as useUserStore } from "../../stores/user-store";
|
||||
import { debounce, useAreFeaturesAvailable } from "@notesnook/common";
|
||||
import { ScopedThemeProvider } from "../theme-provider";
|
||||
import { useStore as useThemeStore } from "../../stores/theme-store";
|
||||
@@ -65,6 +66,8 @@ import { EDITOR_ZOOM } from "./common";
|
||||
import { ScrollContainer } from "@notesnook/ui";
|
||||
import { showFeatureNotAllowedToast } from "../../common/toasts";
|
||||
import { UpgradeDialog } from "../../dialogs/buy-dialog/upgrade-dialog";
|
||||
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
export type OnChangeHandler = (
|
||||
content: () => string,
|
||||
@@ -185,7 +188,6 @@ function TipTap(props: TipTapProps) {
|
||||
|
||||
const autoSave = useRef(true);
|
||||
const { toolbarConfig } = useToolbarConfig();
|
||||
|
||||
const features = useAreFeaturesAvailable([
|
||||
"callout",
|
||||
"outlineList",
|
||||
@@ -196,9 +198,19 @@ function TipTap(props: TipTapProps) {
|
||||
claims: {
|
||||
callout: !!features?.callout?.isAllowed,
|
||||
outlineList: !!features?.outlineList?.isAllowed,
|
||||
taskList: !!features?.taskList?.isAllowed
|
||||
taskList: !!features?.taskList?.isAllowed,
|
||||
insertAttachment: !!useUserStore.getState().isLoggedIn
|
||||
},
|
||||
onPermissionDenied: (claim, silent) => {
|
||||
if (claim === "insertAttachment") {
|
||||
ConfirmDialog.show({
|
||||
title: strings.notLoggedIn(),
|
||||
message: strings.loginToUploadAttachments(),
|
||||
positiveButtonText: strings.okay()
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (silent) {
|
||||
console.log(features, features?.[claim]);
|
||||
if (features?.[claim]) showFeatureNotAllowedToast(features[claim]);
|
||||
|
||||
@@ -82,6 +82,7 @@ import { mdToHtml } from "../../utils/md";
|
||||
import { InboxSettings } from "./inbox-settings";
|
||||
import { withFeatureCheck } from "../../common";
|
||||
import { NotesnookCircleSettings } from "./notesnook-circle-settings";
|
||||
import { hashNavigate } from "../../navigation";
|
||||
|
||||
type SettingsDialogProps = BaseDialogProps<false> & {
|
||||
activeSection?: SectionKeys;
|
||||
@@ -271,6 +272,12 @@ function SettingsSideBar(props: SettingsSideBarProps) {
|
||||
const [route, setRoute] = useState<SectionKeys>(activeSection || "profile");
|
||||
useUserStore((store) => store.isLoggedIn);
|
||||
|
||||
useEffect(() => {
|
||||
hashNavigate(`/settings/${route}`, {
|
||||
notify: false
|
||||
});
|
||||
}, [route, activeSection]);
|
||||
|
||||
return (
|
||||
<FlexScrollContainer
|
||||
id="settings-side-menu"
|
||||
|
||||
@@ -20,29 +20,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { FeatureId } from "@notesnook/common";
|
||||
import { Icon } from "../../components/icons";
|
||||
|
||||
export type SectionKeys =
|
||||
| "profile"
|
||||
| "auth"
|
||||
| "subscription"
|
||||
| "sync"
|
||||
| "appearance"
|
||||
| "behaviour"
|
||||
| "desktop"
|
||||
| "notifications"
|
||||
| "servers"
|
||||
| "editor"
|
||||
| "backup-export"
|
||||
| "export"
|
||||
| "importer"
|
||||
| "vault"
|
||||
| "app-lock"
|
||||
| "privacy"
|
||||
| "support"
|
||||
| "legal"
|
||||
| "developer"
|
||||
| "about"
|
||||
| "inbox"
|
||||
| "circle";
|
||||
const SectionKeys = [
|
||||
"profile",
|
||||
"auth",
|
||||
"subscription",
|
||||
"sync",
|
||||
"appearance",
|
||||
"behaviour",
|
||||
"desktop",
|
||||
"notifications",
|
||||
"servers",
|
||||
"editor",
|
||||
"backup-export",
|
||||
"export",
|
||||
"importer",
|
||||
"vault",
|
||||
"app-lock",
|
||||
"privacy",
|
||||
"support",
|
||||
"legal",
|
||||
"developer",
|
||||
"about",
|
||||
"inbox",
|
||||
"circle"
|
||||
] as const;
|
||||
|
||||
export type SectionKeys = (typeof SectionKeys)[number];
|
||||
|
||||
export type SectionGroupKeys =
|
||||
| "account"
|
||||
@@ -153,3 +156,7 @@ export type TextInputSettingComponent = BaseSettingComponent<"input"> & {
|
||||
export type CustomSettingComponent = BaseSettingComponent<"custom"> & {
|
||||
component: () => JSX.Element | null;
|
||||
};
|
||||
|
||||
export function isSectionKey(key: string): key is SectionKeys {
|
||||
return SectionKeys.includes(key as SectionKeys);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
import { FeatureDialog } from "../dialogs/feature-dialog";
|
||||
import { CreateTagDialog } from "../dialogs/item-dialog";
|
||||
import { OnboardingDialog } from "../dialogs/onboarding-dialog";
|
||||
import { isSectionKey, SectionKeys } from "../dialogs/settings/types";
|
||||
|
||||
const hashroutes = defineHashRoutes({
|
||||
"/": () => {},
|
||||
@@ -68,6 +69,11 @@ const hashroutes = defineHashRoutes({
|
||||
},
|
||||
"/settings": () => {
|
||||
SettingsDialog.show({}).then(afterAction);
|
||||
},
|
||||
"/settings/:section": ({ section }) => {
|
||||
SettingsDialog.show(
|
||||
isSectionKey(section) ? { activeSection: section as SectionKeys } : {}
|
||||
).then(afterAction);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
8
docs/help/contents/faqs/login-to-upload-attachments.md
Normal file
8
docs/help/contents/faqs/login-to-upload-attachments.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Login to upload attachments
|
||||
description: We require users to be logged in to upload attachments.
|
||||
---
|
||||
|
||||
# Login to upload attachments
|
||||
|
||||
We require users to be logged in to upload attachments. This is because attachments are encrypted using a sub-key derived from your database encryption key. Without a login, we cannot encrypt/upload/sync attachments.
|
||||
@@ -84,3 +84,4 @@ navigation:
|
||||
children:
|
||||
- path: faqs/what-are-merge-conflicts.md
|
||||
- path: faqs/is-there-an-eta.md
|
||||
- paht: faqs/login-to-upload-attachments.md
|
||||
|
||||
246
packages/clipper/package-lock.json
generated
246
packages/clipper/package-lock.json
generated
@@ -19,13 +19,51 @@
|
||||
"slugify": "1.6.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.6.0.tgz",
|
||||
"integrity": "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.1.0",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz",
|
||||
"integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
|
||||
"integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@module-federation/error-codes": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.18.0.tgz",
|
||||
"integrity": "sha512-Woonm8ehyVIUPXChmbu80Zj6uJkC0dD9SJUZ/wOPtO8iiz/m+dkrOugAuKgoiR6qH4F+yorWila954tBz4uKsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@module-federation/runtime": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.18.0.tgz",
|
||||
"integrity": "sha512-+C4YtoSztM7nHwNyZl6dQKGUVJdsPrUdaf3HIKReg/GQbrt9uvOlUWo2NXMZ8vDAnf/QRrpSYAwXHmWDn9Obaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -36,6 +74,8 @@
|
||||
},
|
||||
"node_modules/@module-federation/runtime-core": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.18.0.tgz",
|
||||
"integrity": "sha512-ZyYhrDyVAhUzriOsVfgL6vwd+5ebYm595Y13KeMf6TKDRoUHBMTLGQ8WM4TDj8JNsy7LigncK8C03fn97of0QQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -45,6 +85,8 @@
|
||||
},
|
||||
"node_modules/@module-federation/runtime-tools": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.18.0.tgz",
|
||||
"integrity": "sha512-fSga9o4t1UfXNV/Kh6qFvRyZpPp3EHSPRISNeyT8ZoTpzDNiYzhtw0BPUSSD8m6C6XQh2s/11rI4g80UY+d+hA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -54,11 +96,15 @@
|
||||
},
|
||||
"node_modules/@module-federation/sdk": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.18.0.tgz",
|
||||
"integrity": "sha512-Lo/Feq73tO2unjmpRfyyoUkTVoejhItXOk/h5C+4cistnHbTV8XHrW/13fD5e1Iu60heVdAhhelJd6F898Ve9A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@module-federation/webpack-bundler-runtime": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.18.0.tgz",
|
||||
"integrity": "sha512-TEvErbF+YQ+6IFimhUYKK3a5wapD90d90sLsNpcu2kB3QGT7t4nIluE25duXuZDVUKLz86tEPrza/oaaCWTpvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -67,14 +113,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mozilla/readability": {
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.4.4.tgz",
|
||||
"integrity": "sha512-MCgZyANpJ6msfvVMi6+A0UAsvZj//4OHREYUB9f2087uXHVoU+H+SWhuihvb1beKpM323bReQPRio0WNk2+V6g==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz",
|
||||
"integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.5.0",
|
||||
"@emnapi/runtime": "^1.5.0",
|
||||
"@tybys/wasm-util": "^0.10.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz",
|
||||
"integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -89,6 +152,8 @@
|
||||
},
|
||||
"node_modules/@rsbuild/core": {
|
||||
"version": "1.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.17.tgz",
|
||||
"integrity": "sha512-tHa4puv+pEooQvSewu/K5sm270nkVPcP07Ioz1c+fbFCrFpiZWV5XumgznilS80097glUrieN+9xTbIHGXjThQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -107,6 +172,8 @@
|
||||
},
|
||||
"node_modules/@rspack/binding": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.8.tgz",
|
||||
"integrity": "sha512-/91CzhRl9r5BIQCgGsS7jA6MDbw1I2BQpbfcUUdkdKl2P79K3Zo/Mw/TvKzS86catwLaUQEgkGRmYawOfPg7ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
@@ -122,8 +189,136 @@
|
||||
"@rspack/binding-win32-x64-msvc": "1.5.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-arm64": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.8.tgz",
|
||||
"integrity": "sha512-spJfpOSN3f7V90ic45/ET2NKB2ujAViCNmqb0iGurMNQtFRq+7Kd+jvVKKGXKBHBbsQrFhidSWbbqy2PBPGK8g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-x64": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.8.tgz",
|
||||
"integrity": "sha512-YFOzeL1IBknBcri8vjUp43dfUBylCeQnD+9O9p0wZmLAw7DtpN5JEOe2AkGo8kdTqJjYKI+cczJPKIw6lu1LWw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-gnu": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.8.tgz",
|
||||
"integrity": "sha512-UAWCsOnpkvy8eAVRo0uipbHXDhnoDq5zmqWTMhpga0/a3yzCp2e+fnjZb/qnFNYb5MeL0O1mwMOYgn1M3oHILQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-musl": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.8.tgz",
|
||||
"integrity": "sha512-GnSvGT4GjokPSD45cTtE+g7LgghuxSP1MRmvd+Vp/I8pnxTVSTsebRod4TAqyiv+l11nuS8yqNveK9qiOkBLWw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-gnu": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.8.tgz",
|
||||
"integrity": "sha512-XLxh5n/pzUfxsugz/8rVBv+Tx2nqEM+9rharK69kfooDsQNKyz7PANllBQ/v4svJ+W0BRHnDL4qXSGdteZeEjA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-musl": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.8.tgz",
|
||||
"integrity": "sha512-gE0+MZmwF+01p9/svpEESkzkLpBkVUG2o03YMpwXYC/maeRRhWvF8BJ7R3i/Ls/jFGSE87dKX5NbRLVzqksq/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-wasm32-wasi": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.8.tgz",
|
||||
"integrity": "sha512-cfg3niNHeJuxuml1Vy9VvaJrI/5TakzoaZvKX2g5S24wfzR50Eyy4JAsZ+L2voWQQp1yMJbmPYPmnTCTxdJQBQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@napi-rs/wasm-runtime": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-arm64-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-7i3ZTHFXKfU/9Jm9XhpMkrdkxO7lfeYMNVEGkuU5dyBfRMQj69dRgPL7zJwc2plXiqu9LUOl+TwDNTjap7Q36g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-ia32-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-7ZPPWO11J+soea1+mnfaPpQt7GIodBM7A86dx6PbXgVEoZmetcWPrCF2NBfXxQWOKJ9L3RYltC4z+ZyXRgMOrw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-x64-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-N/zXQgzIxME3YUzXT8qnyzxjqcnXudWOeDh8CAG9zqTCnCiy16SFfQ/cQgEoLlD9geQntV6jx2GbDDI5kpDGMQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -136,6 +331,8 @@
|
||||
},
|
||||
"node_modules/@rspack/core": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.5.8.tgz",
|
||||
"integrity": "sha512-sUd2LfiDhqYVfvknuoz0+/c+wSpn693xotnG5g1CSWKZArbtwiYzBIVnNlcHGmuoBRsnj/TkSq8dTQ7gwfBroQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -157,6 +354,8 @@
|
||||
},
|
||||
"node_modules/@rspack/lite-tapable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.1.tgz",
|
||||
"integrity": "sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -165,14 +364,30 @@
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
|
||||
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.46.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz",
|
||||
"integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
@@ -181,12 +396,31 @@
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hyperapp": {
|
||||
"version": "2.0.22",
|
||||
"resolved": "https://registry.npmjs.org/hyperapp/-/hyperapp-2.0.22.tgz",
|
||||
"integrity": "sha512-3uf9HjnjrhbfykowFNEObZewBEo4DXJIM+9FnGkiR9E4H2eh2f921SzMCMS69X5nN3A7KFfmZc9KCKh/7TQBFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -195,6 +429,8 @@
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz",
|
||||
"integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -212,6 +448,8 @@
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.48.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz",
|
||||
"integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -223,6 +461,8 @@
|
||||
},
|
||||
"node_modules/slugify": {
|
||||
"version": "1.6.6",
|
||||
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
|
||||
"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -231,6 +471,8 @@
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ const Tiptap = ({
|
||||
claims: {
|
||||
callout: !!settings.features?.callout?.isAllowed,
|
||||
outlineList: !!settings.features?.outlineList?.isAllowed,
|
||||
taskList: !!settings.features?.taskList?.isAllowed
|
||||
taskList: !!settings.features?.taskList?.isAllowed,
|
||||
insertAttachment: settings.loggedIn
|
||||
},
|
||||
onPermissionDenied: (claim) => {
|
||||
post(
|
||||
|
||||
@@ -73,9 +73,10 @@ function Title({
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
resizeTextarea();
|
||||
setTimeout(() => {
|
||||
resizeTextarea();
|
||||
}, 300);
|
||||
}, 100);
|
||||
}
|
||||
}, [loading, resizeTextarea]);
|
||||
|
||||
@@ -154,6 +155,9 @@ function Title({
|
||||
onPaste={() => {
|
||||
resizeTextarea();
|
||||
}}
|
||||
onCut={() => {
|
||||
resizeTextarea();
|
||||
}}
|
||||
placeholder={titlePlaceholder}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -34,7 +34,8 @@ const initialState = {
|
||||
fontFamily: "sans-serif",
|
||||
fontSize: 16,
|
||||
timeFormat: "12-hour",
|
||||
dateFormat: "DD-MM-YYYY"
|
||||
dateFormat: "DD-MM-YYYY",
|
||||
loggedIn: false
|
||||
};
|
||||
|
||||
global.settingsController = {
|
||||
|
||||
@@ -53,6 +53,7 @@ export type Settings = {
|
||||
fontScale: number;
|
||||
markdownShortcuts: boolean;
|
||||
features: Record<any, any>;
|
||||
loggedIn: boolean;
|
||||
};
|
||||
|
||||
/* eslint-disable no-var */
|
||||
|
||||
@@ -23,6 +23,7 @@ import { createNodeView } from "../react/index.js";
|
||||
import { AttachmentComponent } from "./component.js";
|
||||
import { Attachment } from "./types.js";
|
||||
import { tiptapKeys } from "@notesnook/common";
|
||||
import { hasPermission } from "../../types.js";
|
||||
|
||||
export type AttachmentType = "image" | "file" | "camera";
|
||||
export interface AttachmentOptions {
|
||||
@@ -110,6 +111,10 @@ export const AttachmentNode = Node.create<AttachmentOptions>({
|
||||
insertAttachment:
|
||||
(attachment) =>
|
||||
({ commands, state }) => {
|
||||
if (!hasPermission("insertAttachment")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { $from } = state.selection;
|
||||
const maybeAttachmentNode = state.doc.nodeAt($from.pos);
|
||||
if (maybeAttachmentNode?.type === this.type) {
|
||||
|
||||
@@ -258,10 +258,10 @@ export const Callout = Node.create({
|
||||
container.onmousedown = onClick;
|
||||
container.ontouchstart = onClick;
|
||||
|
||||
if (node.attrs.hiddenUnder) {
|
||||
container.dataset.hiddenUnder = node.attrs.hiddenUnder;
|
||||
if (node.attrs.hidden) {
|
||||
container.dataset.hidden = node.attrs.hidden;
|
||||
} else {
|
||||
delete container.dataset.hiddenUnder;
|
||||
delete container.dataset.hidden;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -275,9 +275,9 @@ export const Callout = Node.create({
|
||||
if (updatedNode.attrs.collapsed) container.classList.add("collapsed");
|
||||
else container.classList.remove("collapsed");
|
||||
|
||||
if (updatedNode.attrs.hiddenUnder)
|
||||
container.dataset.hiddenUnder = updatedNode.attrs.hiddenUnder;
|
||||
else delete container.dataset.hiddenUnder;
|
||||
if (updatedNode.attrs.hidden)
|
||||
container.dataset.hidden = updatedNode.attrs.hidden;
|
||||
else delete container.dataset.hidden;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
|
||||
compareCaretPosition(prev.caretPosition, next.caretPosition) ||
|
||||
prev.language !== next.language ||
|
||||
prev.indentType !== next.indentType ||
|
||||
prev.hiddenUnder !== next.hiddenUnder
|
||||
prev.hidden !== next.hidden
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -89,14 +89,14 @@ export const Heading = TiptapHeading.extend({
|
||||
{
|
||||
types: COLLAPSIBLE_BLOCK_TYPES,
|
||||
attributes: {
|
||||
hiddenUnder: {
|
||||
default: null,
|
||||
hidden: {
|
||||
default: false,
|
||||
keepOnSplit: false,
|
||||
parseHTML: (element) => element.dataset.hiddenUnder || null,
|
||||
parseHTML: (element) => element.dataset.hidden === "true",
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.hiddenUnder) return {};
|
||||
if (!attributes.hidden) return {};
|
||||
return {
|
||||
"data-hidden-under": attributes.hiddenUnder
|
||||
"data-hidden": attributes.hidden === true
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -200,16 +200,9 @@ export const Heading = TiptapHeading.extend({
|
||||
if (currentNode && currentNode.type.name === "heading") {
|
||||
const shouldCollapse = !currentNode.attrs.collapsed;
|
||||
const headingLevel = currentNode.attrs.level;
|
||||
const headingId = currentNode.attrs.blockId;
|
||||
|
||||
tr.setNodeAttribute(pos, "collapsed", shouldCollapse);
|
||||
toggleNodesUnderHeading(
|
||||
tr,
|
||||
pos,
|
||||
headingLevel,
|
||||
shouldCollapse,
|
||||
headingId
|
||||
);
|
||||
toggleNodesUnderHeading(tr, pos, headingLevel, shouldCollapse);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -234,9 +227,9 @@ export const Heading = TiptapHeading.extend({
|
||||
if (updatedNode.attrs.collapsed) heading.dataset.collapsed = "true";
|
||||
else delete heading.dataset.collapsed;
|
||||
|
||||
if (updatedNode.attrs.hiddenUnder)
|
||||
heading.dataset.hiddenUnder = updatedNode.attrs.hiddenUnder;
|
||||
else delete heading.dataset.hiddenUnder;
|
||||
if (updatedNode.attrs.hidden)
|
||||
heading.dataset.hidden = updatedNode.attrs.hidden;
|
||||
else delete heading.dataset.hidden;
|
||||
|
||||
if (updatedNode.attrs.textAlign)
|
||||
heading.style.textAlign =
|
||||
@@ -259,8 +252,7 @@ function toggleNodesUnderHeading(
|
||||
tr: Transaction,
|
||||
headingPos: number,
|
||||
headingLevel: number,
|
||||
isCollapsing: boolean,
|
||||
headingId: string
|
||||
isCollapsing: boolean
|
||||
) {
|
||||
const { doc } = tr;
|
||||
const headingNode = doc.nodeAt(headingPos);
|
||||
@@ -269,6 +261,8 @@ function toggleNodesUnderHeading(
|
||||
let nextPos = headingPos + headingNode.nodeSize;
|
||||
const cursorPos = tr.selection.from;
|
||||
let shouldMoveCursor = false;
|
||||
let insideCollapsedHeading = false;
|
||||
let nestedHeadingLevel: number | null = null;
|
||||
|
||||
while (nextPos < doc.content.size) {
|
||||
const nextNode = doc.nodeAt(nextPos);
|
||||
@@ -289,15 +283,33 @@ function toggleNodesUnderHeading(
|
||||
shouldMoveCursor = true;
|
||||
}
|
||||
|
||||
const currentPos = nextPos;
|
||||
nextPos += nextNode.nodeSize;
|
||||
|
||||
if (COLLAPSIBLE_BLOCK_TYPES.includes(nextNode.type.name)) {
|
||||
if (isCollapsing && typeof nextNode.attrs.hiddenUnder !== "string") {
|
||||
tr.setNodeAttribute(nextPos, "hiddenUnder", headingId);
|
||||
} else if (!isCollapsing && nextNode.attrs.hiddenUnder === headingId) {
|
||||
tr.setNodeAttribute(nextPos, "hiddenUnder", null);
|
||||
if (isCollapsing) {
|
||||
tr.setNodeAttribute(currentPos, "hidden", true);
|
||||
} else {
|
||||
if (insideCollapsedHeading) {
|
||||
if (
|
||||
nextNode.type.name === "heading" &&
|
||||
nestedHeadingLevel !== null &&
|
||||
nextNode.attrs.level <= nestedHeadingLevel
|
||||
) {
|
||||
insideCollapsedHeading = false;
|
||||
nestedHeadingLevel = null;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
tr.setNodeAttribute(currentPos, "hidden", false);
|
||||
if (nextNode.type.name === "heading" && nextNode.attrs.collapsed) {
|
||||
insideCollapsedHeading = true;
|
||||
nestedHeadingLevel = nextNode.attrs.level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextPos += nextNode.nodeSize;
|
||||
}
|
||||
|
||||
if (shouldMoveCursor) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import { createNodeView } from "../react/index.js";
|
||||
import { TextDirections } from "../text-direction/index.js";
|
||||
import { ImageComponent } from "./component.js";
|
||||
import { tiptapKeys } from "@notesnook/common";
|
||||
import { DOMParser } from "@tiptap/pm/model";
|
||||
import { hasPermission } from "../../types.js";
|
||||
|
||||
export interface ImageOptions {
|
||||
inline: boolean;
|
||||
@@ -159,6 +159,10 @@ export const ImageNode = Node.create<ImageOptions>({
|
||||
insertImage:
|
||||
(options) =>
|
||||
({ commands, state }) => {
|
||||
if (!hasPermission("insertAttachment")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { $from } = state.selection;
|
||||
const maybeImageNode = state.doc.nodeAt($from.pos);
|
||||
if (maybeImageNode?.type === this.type) {
|
||||
|
||||
@@ -125,10 +125,10 @@ export class MathView implements NodeView, ICursorPosObserver {
|
||||
if (options.className) this.dom.classList.add(options.className);
|
||||
this.dom.classList.add("math-node");
|
||||
|
||||
if (node.attrs.hiddenUnder) {
|
||||
this.dom.dataset.hiddenUnder = node.attrs.hiddenUnder;
|
||||
if (node.attrs.hidden) {
|
||||
this.dom.dataset.hidden = node.attrs.hidden;
|
||||
} else {
|
||||
delete this.dom.dataset.hiddenUnder;
|
||||
delete this.dom.dataset.hidden;
|
||||
}
|
||||
|
||||
this._mathRenderElt = document.createElement("span");
|
||||
|
||||
@@ -128,3 +128,5 @@ exports[`outline list item > code block in outline list item 1`] = `
|
||||
"type": "doc",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`outline list item > inline image as first child in the old outline list item 1`] = `"<ul data-type="outlineList"><li data-type="outlineListItem"><p data-spacing="double">item 1</p></li><li data-type="outlineListItem"><p data-spacing="double"></p><img src="image.png" data-aspect-ratio="1"></li></ul>"`;
|
||||
|
||||
@@ -28,6 +28,8 @@ import { test, expect, describe, beforeAll, vi } from "vitest";
|
||||
import { OutlineList } from "../../outline-list/outline-list.js";
|
||||
import { OutlineListItem } from "../outline-list-item.js";
|
||||
import { CodeBlock } from "../../code-block/code-block.js";
|
||||
import { Paragraph } from "../../paragraph/paragraph.js";
|
||||
import { ImageNode } from "../../image/image.js";
|
||||
|
||||
describe("outline list item", () => {
|
||||
beforeAll(() => {
|
||||
@@ -70,4 +72,30 @@ describe("outline list item", () => {
|
||||
|
||||
expect(editor.getJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
/**
|
||||
* Two changes happened:
|
||||
* 1. Images were converted from inline nodes to block nodes (https://github.com/streetwriters/notesnook/pull/8563)
|
||||
* 2. Outline list item's `content` schema was changed from `paragraph + list?` to `block+` to `paragraph block*` (https://github.com/streetwriters/notesnook/pull/8772 and https://github.com/streetwriters/notesnook/commit/0b943d8ecdf04fd7d996fd0a4b1d62ec9569f071)
|
||||
*
|
||||
* In the old editor, it was possible to have an inline image as the first item in the outline list item, but based on the new schema it is not possible anymore. So the editor should insert an empty paragraph before the image.
|
||||
*/
|
||||
test("inline image as first child in the old outline list item", async () => {
|
||||
const el = outlineList(
|
||||
outlineListItem(["item 1"]),
|
||||
outlineListItem([h("img", [], { src: "image.png" })])
|
||||
);
|
||||
|
||||
const { editor } = createEditor({
|
||||
initialContent: el.outerHTML,
|
||||
extensions: {
|
||||
outlineList: OutlineList,
|
||||
outlineListItem: OutlineListItem,
|
||||
paragraph: Paragraph,
|
||||
image: ImageNode
|
||||
}
|
||||
});
|
||||
|
||||
expect(editor.getHTML()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
import { OutlineList } from "../outline-list/outline-list.js";
|
||||
import { keybindings, tiptapKeys } from "@notesnook/common";
|
||||
import { Paragraph } from "../paragraph/paragraph.js";
|
||||
import { DOMParser } from "@tiptap/pm/model";
|
||||
|
||||
export interface ListItemOptions {
|
||||
HTMLAttributes: Record<string, unknown>;
|
||||
@@ -64,7 +65,18 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
return [
|
||||
{
|
||||
priority: 100,
|
||||
tag: `li[data-type="${this.name}"]`
|
||||
tag: `li[data-type="${this.name}"]`,
|
||||
getContent: (node, schema) => {
|
||||
const parser = DOMParser.fromSchema(schema);
|
||||
const fragment = parser.parse(node).content;
|
||||
const firstNode = fragment.firstChild;
|
||||
if (firstNode && firstNode.type.name !== "paragraph") {
|
||||
const emptyParagraph = schema.nodes.paragraph.create();
|
||||
return fragment.addToStart(emptyParagraph);
|
||||
}
|
||||
|
||||
return fragment;
|
||||
}
|
||||
}
|
||||
];
|
||||
},
|
||||
@@ -154,6 +166,7 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
const resolvedPos = editor.state.doc.resolve(pos);
|
||||
if (isClickWithinBounds(e, resolvedPos, "left")) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
editor.commands.command(({ tr }) => {
|
||||
tr.setNodeAttribute(
|
||||
pos,
|
||||
|
||||
@@ -112,10 +112,10 @@ export class ReactNodeView<P extends ReactNodeViewProps> implements NodeView {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.node.attrs.hiddenUnder) {
|
||||
this.domRef.dataset.hiddenUnder = this.node.attrs.hiddenUnder;
|
||||
if (this.node.attrs.hidden) {
|
||||
this.domRef.dataset.hidden = this.node.attrs.hidden;
|
||||
} else {
|
||||
delete this.domRef.dataset.hiddenUnder;
|
||||
delete this.domRef.dataset.hidden;
|
||||
}
|
||||
|
||||
portalProviderAPI.render(this.Component, this.domRef);
|
||||
|
||||
@@ -30,7 +30,8 @@ export type PermissionHandlerOptions = {
|
||||
const ClaimsMap = {
|
||||
callout: ["setCallout"] as (keyof UnionCommands)[],
|
||||
outlineList: ["toggleOutlineList"] as (keyof UnionCommands)[],
|
||||
taskList: ["toggleTaskList"] as (keyof UnionCommands)[]
|
||||
taskList: ["toggleTaskList"] as (keyof UnionCommands)[],
|
||||
insertAttachment: ["insertAttachment"] as (keyof UnionCommands)[]
|
||||
};
|
||||
|
||||
export function usePermissionHandler(options: PermissionHandlerOptions) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Popup } from "../components/popup.js";
|
||||
import { downloadImage, toDataURL } from "../../utils/downloader.js";
|
||||
import { useToolbarStore } from "../stores/toolbar-store.js";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { hasPermission } from "../../types.js";
|
||||
|
||||
export type ImageUploadPopupProps = {
|
||||
onInsert: (image: Partial<ImageAttributes>) => void;
|
||||
@@ -46,6 +47,10 @@ export function ImageUploadPopup(props: ImageUploadPopupProps) {
|
||||
title: strings.insert(),
|
||||
disabled: !url,
|
||||
onClick: async () => {
|
||||
if (!hasPermission("insertAttachment")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setIsDownloading(true);
|
||||
setError(undefined);
|
||||
|
||||
|
||||
@@ -707,11 +707,6 @@ p > *::selection {
|
||||
mask-size: cover;
|
||||
}
|
||||
|
||||
.simple-checklist > li.checked > p {
|
||||
opacity: 0.8;
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
|
||||
/* Callout */
|
||||
.ProseMirror div.callout {
|
||||
padding: 15px;
|
||||
@@ -983,7 +978,7 @@ del.diffdel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-hidden-under] {
|
||||
[data-hidden="true"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -3699,6 +3699,10 @@ msgstr "Login successful"
|
||||
msgid "Login to encrypt and sync notes"
|
||||
msgstr "Login to encrypt and sync notes"
|
||||
|
||||
#: src/strings.ts:2608
|
||||
msgid "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||
msgstr "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||
|
||||
#: src/strings.ts:541
|
||||
msgid "Login to your account"
|
||||
msgstr "Login to your account"
|
||||
|
||||
@@ -3679,6 +3679,10 @@ msgstr ""
|
||||
msgid "Login to encrypt and sync notes"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2608
|
||||
msgid "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:541
|
||||
msgid "Login to your account"
|
||||
msgstr ""
|
||||
|
||||
@@ -2603,5 +2603,7 @@ Use this if changes from other devices are not appearing on this device. This wi
|
||||
finishPurchaseInBrowser: () => t`Finish your purchase in the browser.`,
|
||||
goBack: () => t`Go back`,
|
||||
clickToDirectlyClaimPromo: () =>
|
||||
t`Click here to directly claim the promotion.`
|
||||
t`Click here to directly claim the promotion.`,
|
||||
loginToUploadAttachments: () =>
|
||||
t`Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)`
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user