mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-30 10:39:07 +02:00
Compare commits
2 Commits
fix-cache-
...
mobile--fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f56c6e4484 | ||
|
|
74f51085d1 |
20
.github/workflows/core.tests.yml
vendored
20
.github/workflows/core.tests.yml
vendored
@@ -9,13 +9,7 @@ on:
|
||||
- "packages/core/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/core.tests.yml"
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "packages/core/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/core.tests.yml"
|
||||
pull_request:
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
@@ -23,21 +17,11 @@ on:
|
||||
- "reopened"
|
||||
|
||||
jobs:
|
||||
authorize:
|
||||
environment: ${{ github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
'external' || 'internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo true
|
||||
|
||||
test:
|
||||
needs: authorize
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
|
||||
6
.github/workflows/desktop.tests.yml
vendored
6
.github/workflows/desktop.tests.yml
vendored
@@ -10,12 +10,6 @@ on:
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/desktop.tests.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "app/desktop/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/desktop.tests.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
6
.github/workflows/editor.tests.yml
vendored
6
.github/workflows/editor.tests.yml
vendored
@@ -10,12 +10,6 @@ on:
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/editor.tests.yml"
|
||||
pull_request:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "packages/editor/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/editor.tests.yml"
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
|
||||
21
.github/workflows/web.tests.yml
vendored
21
.github/workflows/web.tests.yml
vendored
@@ -9,13 +9,7 @@ on:
|
||||
- "apps/web/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/web.tests.yml"
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- "apps/web/**"
|
||||
# re-run workflow if workflow file changes
|
||||
- ".github/workflows/web.tests.yml"
|
||||
pull_request:
|
||||
types:
|
||||
- "ready_for_review"
|
||||
- "opened"
|
||||
@@ -23,23 +17,12 @@ on:
|
||||
- "reopened"
|
||||
|
||||
jobs:
|
||||
authorize:
|
||||
environment: ${{ github.event_name == 'pull_request_target' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
'external' || 'internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo true
|
||||
|
||||
build:
|
||||
needs: authorize
|
||||
name: Build
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: ./.github/actions/setup-node-with-cache
|
||||
@@ -71,8 +54,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -24,7 +24,7 @@ Requirements:
|
||||
|
||||
Before you can do anything, you'll need to [install Node.js](https://nodejs.org/en/download/) v16 or later on your system.
|
||||
|
||||
1. `clone` the monorepo:
|
||||
Once you have completed the setup, the first step is to `clone` the monorepo:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/streetwriters/notesnook.git
|
||||
@@ -33,28 +33,19 @@ git clone https://github.com/streetwriters/notesnook.git
|
||||
cd notesnook
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
Once you are inside the `./notesnook` directory, run the preparation step:
|
||||
|
||||
```bash
|
||||
# this might take a while to complete
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Run the webapp for desktop environment:
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
4. In a separate terminal session, run the desktop app from the root of the project:
|
||||
Now you can finally start the desktop app for development:
|
||||
|
||||
```bash
|
||||
npm run start:desktop
|
||||
```
|
||||
|
||||
### Release mode
|
||||
|
||||
To run the app in release mode:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -17,226 +17,230 @@ 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 { testCleanup, test } from "./test-override.js";
|
||||
import { test } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { Page } from "playwright";
|
||||
import { gt, lt } from "semver";
|
||||
import { describe } from "vitest";
|
||||
|
||||
test("update starts downloading if version is outdated", async ({
|
||||
ctx: { page },
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
test("update starts downloading if version is outdated", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async ({ page }) => {
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /updating/i })
|
||||
.waitFor({ state: "attached" });
|
||||
});
|
||||
|
||||
test("update is only shown if version is outdated and auto updates are disabled", async ({
|
||||
ctx,
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false
|
||||
})
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /updating/i })
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.waitFor({ state: "attached" });
|
||||
});
|
||||
|
||||
describe("update to stable if it is newer", () => {
|
||||
test.scoped({ options: { version: "3.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
test("update is only shown if version is outdated and auto updates are disabled", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
await ctx.relaunch();
|
||||
|
||||
await ctx.relaunch();
|
||||
const { page } = ctx;
|
||||
|
||||
const { page } = ctx;
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
await skipDialog(page);
|
||||
|
||||
await skipDialog(page);
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
expect(gt(version, "3.0.0-beta.0")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("update is not available if it latest stable version is older", () => {
|
||||
test.scoped({ options: { version: "99.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
expect(
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.isHidden()
|
||||
).toBe(true);
|
||||
});
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
});
|
||||
|
||||
describe("downgrade to stable on switching to stable release track", () => {
|
||||
test.scoped({ options: { version: "99.0.0-beta.0" } });
|
||||
test("test", async ({ ctx, expect, onTestFinished }) => {
|
||||
onTestFinished(testCleanup);
|
||||
test("update to stable if it is newer", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "stable"
|
||||
})
|
||||
);
|
||||
await ctx.relaunch();
|
||||
|
||||
await ctx.relaunch();
|
||||
const { page } = ctx;
|
||||
|
||||
const { page } = ctx;
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
await skipDialog(page);
|
||||
|
||||
await skipDialog(page);
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
t.expect(gt(version, "3.0.0-beta.0")).toBe(true);
|
||||
},
|
||||
{ version: "3.0.0-beta.0" }
|
||||
);
|
||||
});
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
test("update is not available if it latest stable version is older", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "beta"
|
||||
})
|
||||
);
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
expect(lt(version, "99.0.0-beta.0")).toBe(true);
|
||||
});
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
t.expect(
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i })
|
||||
.isHidden()
|
||||
).toBe(true);
|
||||
},
|
||||
{ version: "99.0.0-beta.0" }
|
||||
);
|
||||
});
|
||||
|
||||
test("downgrade to stable on switching to stable release track", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async (ctx) => {
|
||||
await ctx.app.close();
|
||||
await writeFile(
|
||||
ctx.configPath,
|
||||
JSON.stringify({
|
||||
automaticUpdates: false,
|
||||
releaseTrack: "stable"
|
||||
})
|
||||
);
|
||||
|
||||
await ctx.relaunch();
|
||||
|
||||
const { page } = ctx;
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
t.expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await skipDialog(page);
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
|
||||
await page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /checking for updates/i })
|
||||
.waitFor({ state: "hidden" });
|
||||
|
||||
const updateButton = page
|
||||
.locator(".theme-scope-statusBar")
|
||||
.getByRole("button", { name: /available/i });
|
||||
await updateButton.waitFor({ state: "visible" });
|
||||
const content = await updateButton.textContent();
|
||||
const version = content?.split(" ")?.[0] || "";
|
||||
t.expect(lt(version, "99.0.0-beta.0")).toBe(true);
|
||||
},
|
||||
{ version: "99.0.0-beta.0" }
|
||||
);
|
||||
});
|
||||
|
||||
async function skipDialog(page: Page) {
|
||||
try {
|
||||
const dialog = page.locator(".ReactModal__Content");
|
||||
const positiveButton = dialog.locator(
|
||||
"button[data-role='positive-button']"
|
||||
);
|
||||
const negativeButton = dialog.locator(
|
||||
"button[data-role='negative-button']"
|
||||
);
|
||||
if (await positiveButton.isVisible())
|
||||
await positiveButton.click({ timeout: 1000 });
|
||||
else if (await negativeButton.isVisible())
|
||||
await negativeButton.click({ timeout: 1000 });
|
||||
} catch (e) {
|
||||
// ignore error
|
||||
}
|
||||
await page
|
||||
.waitForSelector(".ReactModal__Content", {
|
||||
timeout: 1000
|
||||
})
|
||||
.catch(() => {})
|
||||
.then(async () => {
|
||||
const positiveButton = page.locator(
|
||||
"button[data-role='positive-button']"
|
||||
);
|
||||
const negativeButton = page.locator(
|
||||
"button[data-role='negative-button']"
|
||||
);
|
||||
if (await positiveButton.isVisible()) await positiveButton.click();
|
||||
else if (await negativeButton.isVisible()) await negativeButton.click();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { buildApp } from "./utils";
|
||||
|
||||
export default async function setup() {
|
||||
await buildApp();
|
||||
}
|
||||
@@ -17,24 +17,22 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { testCleanup, test } from "./test-override.js";
|
||||
import { test } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import assert from "assert";
|
||||
|
||||
test("make sure app loads", async ({
|
||||
ctx: { page },
|
||||
expect,
|
||||
onTestFinished
|
||||
}) => {
|
||||
onTestFinished(testCleanup);
|
||||
test("make sure app loads", async (t) => {
|
||||
await harness(t, async ({ page }) => {
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
await page.waitForSelector("#authForm");
|
||||
assert.ok(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
);
|
||||
|
||||
expect(
|
||||
await page.getByRole("button", { name: "Create account" }).isVisible()
|
||||
).toBe(true);
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page
|
||||
.getByRole("button", { name: "Skip & go directly to the app" })
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { test as vitestTest, TestContext } from "vitest";
|
||||
import { buildAndLaunchApp, Fixtures, TestOptions } from "./utils";
|
||||
import { mkdir, rm } from "fs/promises";
|
||||
import path from "path";
|
||||
import slugify from "slugify";
|
||||
|
||||
export const test = vitestTest.extend<Fixtures>({
|
||||
options: { version: "3.0.0" } as TestOptions,
|
||||
ctx: async ({ options }, use) => {
|
||||
const ctx = await buildAndLaunchApp(options);
|
||||
await use(ctx);
|
||||
}
|
||||
});
|
||||
|
||||
export async function testCleanup(context: TestContext) {
|
||||
const ctx = (context.task.context as unknown as Fixtures).ctx;
|
||||
if (context.task.result?.state === "fail") {
|
||||
await mkdir("test-results", { recursive: true });
|
||||
await ctx.page.screenshot({
|
||||
path: path.join(
|
||||
"test-results",
|
||||
`${slugify(context.task.name)}-${process.platform}-${
|
||||
process.arch
|
||||
}-error.png`
|
||||
)
|
||||
});
|
||||
}
|
||||
await ctx.app.close();
|
||||
await rm(ctx.userDataDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
maxRetries: 3,
|
||||
retryDelay: 5000
|
||||
}).catch(() => {
|
||||
/*ignore */
|
||||
});
|
||||
await rm(ctx.outputDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
maxRetries: 3,
|
||||
retryDelay: 5000
|
||||
}).catch(() => {
|
||||
/*ignore */
|
||||
});
|
||||
}
|
||||
@@ -18,233 +18,144 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { execSync } from "child_process";
|
||||
import { cp, readFile, writeFile } from "fs/promises";
|
||||
import { mkdir } from "fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path, { join, resolve } from "path";
|
||||
import path from "path";
|
||||
import { _electron as electron } from "playwright";
|
||||
import { existsSync } from "fs";
|
||||
import slugify from "slugify";
|
||||
import { TaskContext } from "vitest";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const IS_DEBUG = process.env.NN_DEBUG === "true" || process.env.CI === "true";
|
||||
const productName = `NotesnookTestHarness`;
|
||||
const SOURCE_DIR = resolve("output", productName);
|
||||
|
||||
export interface AppContext {
|
||||
interface AppContext {
|
||||
app: import("playwright").ElectronApplication;
|
||||
page: import("playwright").Page;
|
||||
configPath: string;
|
||||
userDataDir: string;
|
||||
outputDir: string;
|
||||
relaunch: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface TestOptions {
|
||||
interface TestOptions {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface Fixtures {
|
||||
options: TestOptions;
|
||||
ctx: AppContext;
|
||||
export async function harness(
|
||||
t: TaskContext,
|
||||
cb: (ctx: AppContext) => Promise<void>,
|
||||
options?: TestOptions
|
||||
) {
|
||||
const ctx = await buildAndLaunchApp(options);
|
||||
|
||||
t.onTestFinished(async (result) => {
|
||||
if (result.state === "fail") {
|
||||
await mkdir("test-results", { recursive: true });
|
||||
await ctx.page.screenshot({
|
||||
path: path.join(
|
||||
"test-results",
|
||||
`${slugify(t.task.name)}-${process.platform}-${
|
||||
process.arch
|
||||
}-error.png`
|
||||
)
|
||||
});
|
||||
}
|
||||
await ctx.app.close();
|
||||
});
|
||||
|
||||
await cb(ctx);
|
||||
}
|
||||
|
||||
export async function buildAndLaunchApp(
|
||||
options?: TestOptions
|
||||
): Promise<AppContext> {
|
||||
const productName = `notesnooktest${makeid(10)}`;
|
||||
const outputDir = path.join("test-artifacts", `${productName}-output`);
|
||||
const executablePath = await copyBuild({
|
||||
...options,
|
||||
outputDir
|
||||
});
|
||||
const { app, page, configPath, userDataDir } = await launchApp(
|
||||
executablePath,
|
||||
productName
|
||||
);
|
||||
async function buildAndLaunchApp(options?: TestOptions): Promise<AppContext> {
|
||||
const productName = makeid(10);
|
||||
const executablePath = await buildApp({ ...options, productName });
|
||||
const { app, page, configPath } = await launchApp(executablePath);
|
||||
const ctx: AppContext = {
|
||||
app,
|
||||
page,
|
||||
configPath,
|
||||
userDataDir,
|
||||
outputDir,
|
||||
relaunch: async () => {
|
||||
const { app, page, configPath, userDataDir } = await launchApp(
|
||||
executablePath,
|
||||
productName
|
||||
);
|
||||
const { app, page, configPath } = await launchApp(executablePath);
|
||||
ctx.app = app;
|
||||
ctx.page = page;
|
||||
ctx.userDataDir = userDataDir;
|
||||
ctx.configPath = configPath;
|
||||
}
|
||||
};
|
||||
return ctx;
|
||||
}
|
||||
|
||||
async function launchApp(executablePath: string, packageName: string) {
|
||||
const userDataDir = resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"test-artifacts",
|
||||
"user_data_dirs",
|
||||
packageName
|
||||
);
|
||||
async function launchApp(executablePath: string) {
|
||||
const app = await electron.launch({
|
||||
executablePath,
|
||||
args: IS_DEBUG ? [] : ["--hidden"],
|
||||
env: {
|
||||
...(process.platform === "linux"
|
||||
env:
|
||||
process.platform === "linux"
|
||||
? {
|
||||
...(process.env as Record<string, string>),
|
||||
APPIMAGE: "true"
|
||||
}
|
||||
: (process.env as Record<string, string>)),
|
||||
CUSTOM_USER_DATA_DIR: userDataDir
|
||||
}
|
||||
: (process.env as Record<string, string>)
|
||||
});
|
||||
|
||||
const page = await app.firstWindow();
|
||||
|
||||
const configPath = path.join(userDataDir, "UserData", "config.json");
|
||||
const userDataDirectory = await app.evaluate((a) => {
|
||||
return a.app.getPath("userData");
|
||||
});
|
||||
const configPath = path.join(userDataDirectory, "config.json");
|
||||
return {
|
||||
app,
|
||||
page,
|
||||
configPath,
|
||||
userDataDir
|
||||
configPath
|
||||
};
|
||||
}
|
||||
|
||||
let MAX_RETRIES = 3;
|
||||
export async function buildApp(version?: string) {
|
||||
if (!existsSync(SOURCE_DIR)) {
|
||||
const args = [
|
||||
"electron-builder",
|
||||
"--dir",
|
||||
`--${process.arch}`,
|
||||
`--config electron-builder.config.js`,
|
||||
`--c.extraMetadata.productName=${productName}`,
|
||||
`--c.compression=store`,
|
||||
"--publish=never"
|
||||
];
|
||||
if (version) args.push(`--c.extraMetadata.version=${version}`);
|
||||
try {
|
||||
execSync(`npx ${args.join(" ")}`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore",
|
||||
env: {
|
||||
...process.env,
|
||||
NOTESNOOK_STAGING: "true",
|
||||
NN_PRODUCT_NAME: productName,
|
||||
NN_APP_ID: `com.notesnook.test.${productName}`,
|
||||
NN_OUTPUT_DIR: SOURCE_DIR
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (--MAX_RETRIES) {
|
||||
console.log("retrying...");
|
||||
return await buildApp(version);
|
||||
} else throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyBuild({
|
||||
async function buildApp({
|
||||
version,
|
||||
outputDir
|
||||
productName
|
||||
}: {
|
||||
version?: string;
|
||||
outputDir: string;
|
||||
productName: string;
|
||||
}) {
|
||||
return process.platform === "win32"
|
||||
? await makeBuildCopyWindows(outputDir, productName, version)
|
||||
: process.platform === "darwin"
|
||||
? await makeBuildCopyMacOS(outputDir, productName, version)
|
||||
: await makeBuildCopyLinux(outputDir, productName, version);
|
||||
}
|
||||
|
||||
async function makeBuildCopyLinux(
|
||||
outputDir: string,
|
||||
productName: string,
|
||||
version?: string
|
||||
) {
|
||||
const platformDir =
|
||||
process.arch === "arm64" ? "linux-arm64-unpacked" : "linux-unpacked";
|
||||
const appDir = await makeBuildCopy(
|
||||
outputDir,
|
||||
platformDir,
|
||||
"resources",
|
||||
version
|
||||
);
|
||||
return resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
appDir,
|
||||
productName.toLowerCase().replace(/\s+/g, "-")
|
||||
);
|
||||
}
|
||||
|
||||
async function makeBuildCopyWindows(
|
||||
outputDir: string,
|
||||
productName: string,
|
||||
version?: string
|
||||
) {
|
||||
const platformDir =
|
||||
process.arch === "arm64" ? "win-arm64-unpacked" : "win-unpacked";
|
||||
const appDir = await makeBuildCopy(
|
||||
outputDir,
|
||||
platformDir,
|
||||
"resources",
|
||||
version
|
||||
);
|
||||
return resolve(__dirname, "..", appDir, `${productName}.exe`);
|
||||
}
|
||||
|
||||
async function makeBuildCopyMacOS(
|
||||
outputDir: string,
|
||||
productName: string,
|
||||
version?: string
|
||||
) {
|
||||
const platformDir = process.arch === "arm64" ? "mac-arm64" : "mac";
|
||||
const appDir = await makeBuildCopy(
|
||||
outputDir,
|
||||
platformDir,
|
||||
join(`${productName}.app`, "Contents", "Resources"),
|
||||
version
|
||||
);
|
||||
return resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
appDir,
|
||||
`${productName}.app`,
|
||||
"Contents",
|
||||
"MacOS",
|
||||
productName
|
||||
);
|
||||
}
|
||||
|
||||
async function makeBuildCopy(
|
||||
outputDir: string,
|
||||
platformDir: string,
|
||||
resourcesDir: string,
|
||||
version?: string
|
||||
) {
|
||||
const appDir = outputDir;
|
||||
await cp(join(SOURCE_DIR, platformDir), outputDir, {
|
||||
recursive: true,
|
||||
preserveTimestamps: true,
|
||||
verbatimSymlinks: true,
|
||||
dereference: false,
|
||||
force: true
|
||||
const buildRoot = path.join("test-artifacts", `${productName}-build`);
|
||||
const output = path.join("test-artifacts", `${productName}-output`);
|
||||
execSync(`npm run release -- --root ${buildRoot} --skip-tsc-build`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore"
|
||||
});
|
||||
|
||||
const packageJsonPath = join(appDir, resourcesDir, "app", "package.json");
|
||||
const args = [
|
||||
`--config electron-builder.config.js`,
|
||||
`--c.extraMetadata.productName=${productName}`,
|
||||
"--publish=never"
|
||||
];
|
||||
if (version) args.push(`--c.extraMetadata.version=${version}`);
|
||||
|
||||
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
||||
if (version) {
|
||||
packageJson.version = version;
|
||||
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
||||
}
|
||||
execSync(`npx electron-builder --dir --${process.arch} ${args.join(" ")}`, {
|
||||
stdio: IS_DEBUG ? "inherit" : "ignore",
|
||||
env: {
|
||||
...process.env,
|
||||
NOTESNOOK_STAGING: "true",
|
||||
NN_BUILD_ROOT: buildRoot,
|
||||
NN_PRODUCT_NAME: productName,
|
||||
NN_APP_ID: `com.notesnook.test.${productName}`,
|
||||
NN_OUTPUT_DIR: output
|
||||
}
|
||||
});
|
||||
|
||||
return appDir;
|
||||
return path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
output,
|
||||
process.platform === "linux"
|
||||
? process.arch === "arm64"
|
||||
? "linux-arm64-unpacked"
|
||||
: "linux-unpacked"
|
||||
: process.platform === "darwin"
|
||||
? process.arch === "arm64"
|
||||
? `mac-arm64/${productName}.app/Contents/MacOS/`
|
||||
: `mac/${productName}.app/Contents/MacOS/`
|
||||
: "win-unpacked",
|
||||
process.platform === "win32" ? `${productName}.exe` : productName
|
||||
);
|
||||
}
|
||||
|
||||
function makeid(length: number) {
|
||||
|
||||
1596
apps/desktop/package-lock.json
generated
1596
apps/desktop/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,9 +8,7 @@
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"sideEffects": [
|
||||
"src/overrides.ts"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"require": {
|
||||
@@ -57,7 +55,7 @@
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^7.8.0",
|
||||
"vitest": "^3.2.4"
|
||||
"vitest": "2.1.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 "./overrides";
|
||||
import { app, BrowserWindow, nativeTheme, shell } from "electron";
|
||||
import { isDevelopment } from "./utils";
|
||||
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { app } from "electron";
|
||||
import path from "path";
|
||||
|
||||
if (process.env.CUSTOM_USER_DATA_DIR) {
|
||||
app.setPath(
|
||||
"appData",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "AppData")
|
||||
);
|
||||
app.setPath(
|
||||
"userData",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "UserData")
|
||||
);
|
||||
app.setPath(
|
||||
"documents",
|
||||
path.join(process.env.CUSTOM_USER_DATA_DIR, "Documents")
|
||||
);
|
||||
}
|
||||
@@ -21,13 +21,11 @@ import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
testTimeout: 120 * 1000,
|
||||
hookTimeout: 120 * 1000,
|
||||
testTimeout: process.env.CI ? 120 * 1000 : 120 * 1000,
|
||||
sequence: {
|
||||
concurrent: true,
|
||||
shuffle: true
|
||||
},
|
||||
globalSetup: "./__tests__/global-setup.ts",
|
||||
dir: "./__tests__/",
|
||||
exclude: [
|
||||
"**/node_modules/**",
|
||||
|
||||
@@ -137,7 +137,6 @@ export async function deleteFile(
|
||||
|
||||
export async function clearFileStorage() {
|
||||
try {
|
||||
await createCacheDir();
|
||||
const files = await RNFetchBlob.fs.ls(cacheDir);
|
||||
const oldCache = await RNFetchBlob.fs.ls(cacheDirOld);
|
||||
|
||||
@@ -222,7 +221,6 @@ export async function deleteCacheFileByName(name: string) {
|
||||
}
|
||||
|
||||
export async function deleteDCacheFiles() {
|
||||
await createCacheDir();
|
||||
const files = await RNFetchBlob.fs.ls(cacheDir);
|
||||
for (const file of files) {
|
||||
if (file.includes("_dcache") || file.startsWith("NN_")) {
|
||||
|
||||
@@ -17,15 +17,12 @@ 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 { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Dimensions, TextInput, View } from "react-native";
|
||||
import Orientation from "react-native-orientation-locker";
|
||||
import Pdf from "react-native-pdf";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
|
||||
import downloadAttachment from "../../../common/filesystem/download-attachment";
|
||||
import { deleteCacheFileByPath, exists } from "../../../common/filesystem/io";
|
||||
import { cacheDir } from "../../../common/filesystem/utils";
|
||||
import { useAttachmentProgress } from "../../../hooks/use-attachment-progress";
|
||||
import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
|
||||
@@ -33,9 +30,8 @@ import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../../services/event-manager";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import { Dialog } from "../../dialog";
|
||||
import BaseDialog from "../../dialog/base-dialog";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
@@ -43,6 +39,11 @@ import SheetProvider from "../../sheet-provider";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import { ProgressBarComponent } from "../../ui/svg/lazy";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import { deleteCacheFileByPath } from "../../../common/filesystem/io";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
|
||||
const WIN_WIDTH = Dimensions.get("window").width;
|
||||
const WIN_HEIGHT = Dimensions.get("window").height;
|
||||
@@ -104,19 +105,15 @@ const PDFPreview = () => {
|
||||
const open = useCallback(
|
||||
async (attachment) => {
|
||||
setVisible(true);
|
||||
setLoading(true);
|
||||
setTimeout(async () => {
|
||||
setAttachment(attachment);
|
||||
let hash = attachment.hash;
|
||||
if (!hash) return;
|
||||
if (!(await exists(hash))) setLoading(true);
|
||||
const uri = await downloadAttachment(hash, false, {
|
||||
silent: true,
|
||||
cache: true
|
||||
});
|
||||
if (!(await exists(hash))) {
|
||||
setVisible(false);
|
||||
return;
|
||||
}
|
||||
const path = `${cacheDir}/${uri}`;
|
||||
snapshotValue.current = snapshot.current;
|
||||
setPDFSource("file://" + path);
|
||||
@@ -169,7 +166,8 @@ const PDFPreview = () => {
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<View
|
||||
<Animated.View
|
||||
exiting={FadeOut}
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
@@ -190,7 +188,7 @@ const PDFPreview = () => {
|
||||
>
|
||||
{strings.loadingWithProgress(progress?.percent)}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</Animated.View>
|
||||
) : (
|
||||
<>
|
||||
<View
|
||||
@@ -272,42 +270,49 @@ const PDFPreview = () => {
|
||||
</View>
|
||||
</View>
|
||||
{pdfSource ? (
|
||||
<Pdf
|
||||
source={{
|
||||
uri: pdfSource
|
||||
}}
|
||||
ref={pdfRef}
|
||||
onLoadComplete={(numberOfPages) => {
|
||||
setNumPages(numberOfPages);
|
||||
}}
|
||||
onPageChanged={(page) => {
|
||||
setCurrentPage(page);
|
||||
inputRef.current?.setNativeProps({
|
||||
text: page + ""
|
||||
});
|
||||
saveSnapshot({
|
||||
currentPage: page,
|
||||
scale: snapshot?.current?.scale
|
||||
});
|
||||
}}
|
||||
// scale={snapshotValue.current?.scale}
|
||||
// onScaleChanged={(scale) => {
|
||||
// saveSnapshot({
|
||||
// currentPage: snapshot?.current?.currentPage,
|
||||
// scale: scale
|
||||
// });
|
||||
// }}
|
||||
page={snapshotValue?.current?.currentPage}
|
||||
password={password}
|
||||
maxScale={6}
|
||||
onError={onError}
|
||||
onPressLink={(uri) => {}}
|
||||
<Animated.View
|
||||
style={{
|
||||
flex: 1,
|
||||
width: width,
|
||||
height: Dimensions.get("window").height
|
||||
flex: 1
|
||||
}}
|
||||
/>
|
||||
entering={FadeIn}
|
||||
>
|
||||
<Pdf
|
||||
source={{
|
||||
uri: pdfSource
|
||||
}}
|
||||
ref={pdfRef}
|
||||
onLoadComplete={(numberOfPages) => {
|
||||
setNumPages(numberOfPages);
|
||||
}}
|
||||
onPageChanged={(page) => {
|
||||
setCurrentPage(page);
|
||||
inputRef.current?.setNativeProps({
|
||||
text: page + ""
|
||||
});
|
||||
saveSnapshot({
|
||||
currentPage: page,
|
||||
scale: snapshot?.current?.scale
|
||||
});
|
||||
}}
|
||||
// scale={snapshotValue.current?.scale}
|
||||
// onScaleChanged={(scale) => {
|
||||
// saveSnapshot({
|
||||
// currentPage: snapshot?.current?.currentPage,
|
||||
// scale: scale
|
||||
// });
|
||||
// }}
|
||||
page={snapshotValue?.current?.currentPage}
|
||||
password={password}
|
||||
maxScale={6}
|
||||
onError={onError}
|
||||
onPressLink={(uri) => {}}
|
||||
style={{
|
||||
flex: 1,
|
||||
width: width,
|
||||
height: Dimensions.get("window").height
|
||||
}}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -30,7 +30,6 @@ import { BackHandler, Platform, ViewProps } from "react-native";
|
||||
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
||||
import Animated, {
|
||||
runOnJS,
|
||||
SharedValue,
|
||||
useAnimatedReaction,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
@@ -68,7 +67,6 @@ export interface TabsRef {
|
||||
setScrollEnabled: () => true;
|
||||
isDrawerOpen: () => boolean;
|
||||
node: RefObject<Animated.View>;
|
||||
tabChangedFromSwipeAction: SharedValue<boolean>;
|
||||
}
|
||||
|
||||
export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
@@ -118,7 +116,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
const isLoaded = useRef(false);
|
||||
const prevWidths = useRef(widths);
|
||||
const isIPhone = Platform.OS === "ios";
|
||||
const tabChangedFromSwipeAction = useSharedValue(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (deviceMode === "tablet" || fullscreen) {
|
||||
@@ -194,7 +191,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
: withTiming(editorPosition);
|
||||
currentTab.value = 2;
|
||||
}
|
||||
tabChangedFromSwipeAction.value = false;
|
||||
},
|
||||
goToIndex: (index: number, animated = true) => {
|
||||
if (deviceMode === "tablet") {
|
||||
@@ -214,7 +210,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
: editorPosition;
|
||||
currentTab.value = 2;
|
||||
}
|
||||
tabChangedFromSwipeAction.value = false;
|
||||
},
|
||||
unlock: () => {
|
||||
forcedLock.value = false;
|
||||
@@ -257,8 +252,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
},
|
||||
page: () => (currentTab.value === 1 ? "home" : "editor"),
|
||||
setScrollEnabled: () => true,
|
||||
node: node,
|
||||
tabChangedFromSwipeAction: tabChangedFromSwipeAction
|
||||
node: node
|
||||
}),
|
||||
[
|
||||
currentTab,
|
||||
@@ -268,8 +262,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
homePosition,
|
||||
editorPosition,
|
||||
forcedLock,
|
||||
isDrawerOpen,
|
||||
tabChangedFromSwipeAction
|
||||
isDrawerOpen
|
||||
]
|
||||
);
|
||||
|
||||
@@ -369,20 +362,18 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
isDrawerOpen.value = true;
|
||||
currentTab.value = 1;
|
||||
runOnJS(onDrawerStateChange)(true);
|
||||
tabChangedFromSwipeAction.value = true;
|
||||
return;
|
||||
} else if (!isSwipeLeft && finalValue > 100) {
|
||||
translateX.value = withSpring(homePosition, animationConfig);
|
||||
isDrawerOpen.value = false;
|
||||
currentTab.value = 1;
|
||||
runOnJS(onDrawerStateChange)(false);
|
||||
tabChangedFromSwipeAction.value = true;
|
||||
|
||||
return;
|
||||
} else if (!isSwipeLeft && finalValue < 100) {
|
||||
translateX.value = withSpring(0, animationConfig);
|
||||
isDrawerOpen.value = true;
|
||||
currentTab.value = 1;
|
||||
tabChangedFromSwipeAction.value = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -393,8 +384,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
translateX.value = withSpring(editorPosition, animationConfig);
|
||||
currentTab.value = 2;
|
||||
isDrawerOpen.value = false;
|
||||
|
||||
tabChangedFromSwipeAction.value = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -409,8 +398,6 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
|
||||
translateX.value = withSpring(editorPosition, animationConfig);
|
||||
currentTab.value = 2;
|
||||
}
|
||||
|
||||
tabChangedFromSwipeAction.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ const ColorItem = ({ item, note }: { item: Color; note: Note }) => {
|
||||
testID={notesnook.ids.dialogs.actionsheet.color(item.colorCode)}
|
||||
key={item.id}
|
||||
onPress={toggleColor}
|
||||
onLongPress={(event) => {
|
||||
NativeTooltip.show(event, item.title, NativeTooltip.POSITIONS.TOP);
|
||||
}}
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35,
|
||||
|
||||
@@ -197,6 +197,16 @@ export const SelectionHeader = React.memo(
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: strings.move(),
|
||||
onPress: async () => {
|
||||
const ids = selectedItemsList;
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
MoveNotebook.present(notebooks);
|
||||
},
|
||||
visible: renderedInRoute === "Notebooks",
|
||||
icon: "arrow-right-bold-box-outline"
|
||||
},
|
||||
{
|
||||
title: strings.manageTags(),
|
||||
onPress: async () => {
|
||||
|
||||
@@ -40,7 +40,6 @@ import Sync from "../../../services/sync";
|
||||
|
||||
import Clipboard from "@react-native-clipboard/clipboard";
|
||||
import { logoutUser } from "../../../screens/settings/logout";
|
||||
import { sleep } from "../../../utils/time";
|
||||
export const UserSheet = () => {
|
||||
const ref = useSheetRef();
|
||||
const { colors } = useThemeColors();
|
||||
@@ -311,11 +310,10 @@ export const UserSheet = () => {
|
||||
{
|
||||
icon: "logout",
|
||||
title: strings.logout(),
|
||||
onPress: async () => {
|
||||
onPress: () => {
|
||||
console.log("logout");
|
||||
ref.current?.hide();
|
||||
await sleep(300);
|
||||
logoutUser();
|
||||
ref.current?.hide();
|
||||
},
|
||||
hidden: !user
|
||||
}
|
||||
|
||||
@@ -211,14 +211,6 @@ const TabBar = (
|
||||
const ids = useSideMenuNotebookSelectionStore
|
||||
.getState()
|
||||
.getSelectedItemIds();
|
||||
if (!ids.length) {
|
||||
ToastManager.show({
|
||||
context: "local",
|
||||
type: "error",
|
||||
message: strings.noNotebooksSelectedToMove()
|
||||
});
|
||||
return;
|
||||
}
|
||||
const notebooks = await db.notebooks.all.items(ids);
|
||||
Navigation.navigate("MoveNotebook", {
|
||||
selectedNotebooks: notebooks
|
||||
|
||||
@@ -23,11 +23,13 @@ import { Platform, View } from "react-native";
|
||||
import ActionSheet from "react-native-actions-sheet";
|
||||
import useGlobalSafeAreaInsets from "../../../hooks/use-global-safe-area-insets";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
import { getContainerBorder } from "../../../utils/colors";
|
||||
import { PremiumToast } from "../../premium/premium-toast";
|
||||
import { Toast } from "../../toast";
|
||||
import { NotesnookModule } from "../../../utils/notesnook-module";
|
||||
import { useAppState } from "../../../hooks/use-app-state";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
import { getContainerBorder } from "../../../utils/colors";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} param0
|
||||
@@ -61,10 +63,6 @@ const SheetWrapper = ({
|
||||
const locked = useUserStore((state) => state.appLocked);
|
||||
|
||||
let width = dimensions.width > 600 ? 600 : 500;
|
||||
const isGestureNavigationEnabled =
|
||||
NotesnookModule.isGestureNavigationEnabled();
|
||||
|
||||
console.log(isGestureNavigationEnabled);
|
||||
|
||||
const style = React.useMemo(() => {
|
||||
return {
|
||||
@@ -79,18 +77,14 @@ const SheetWrapper = ({
|
||||
borderBottomRightRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
...getContainerBorder(colors.primary.border, 0.5),
|
||||
borderBottomWidth: 0,
|
||||
paddingBottom: isGestureNavigationEnabled
|
||||
? insets.bottom
|
||||
: insets.bottom || 48
|
||||
borderBottomWidth: 0
|
||||
};
|
||||
}, [
|
||||
colors.primary.background,
|
||||
colors.primary.border,
|
||||
largeTablet,
|
||||
smallTablet,
|
||||
width,
|
||||
insets.bottom
|
||||
width
|
||||
]);
|
||||
|
||||
const _onOpen = () => {
|
||||
|
||||
@@ -19,4 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { FeatureType } from "./components/sheets/new-feature";
|
||||
|
||||
export const features: FeatureType[] = [];
|
||||
export const features: FeatureType[] = [
|
||||
{
|
||||
title: "Improved Search",
|
||||
body: "Improved search results with better relevance and highlighting."
|
||||
}
|
||||
];
|
||||
|
||||
@@ -515,8 +515,6 @@ export const useActions = ({
|
||||
title: strings.addNotebook(),
|
||||
icon: "plus",
|
||||
onPress: async () => {
|
||||
close();
|
||||
await sleep(300);
|
||||
AddNotebookSheet.present(undefined, item);
|
||||
}
|
||||
},
|
||||
@@ -525,8 +523,6 @@ export const useActions = ({
|
||||
title: strings.editNotebook(),
|
||||
icon: "square-edit-outline",
|
||||
onPress: async () => {
|
||||
close();
|
||||
await sleep(300);
|
||||
AddNotebookSheet.present(item);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -30,10 +30,6 @@ import React, {
|
||||
useState
|
||||
} from "react";
|
||||
import { Dimensions, LayoutChangeEvent, Platform, View } from "react-native";
|
||||
import Orientation, {
|
||||
OrientationType,
|
||||
useDeviceOrientationChange
|
||||
} from "react-native-orientation-locker";
|
||||
import Animated, {
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
@@ -71,6 +67,10 @@ import {
|
||||
} from "../utils/events";
|
||||
import { editorRef, fluidTabsRef } from "../utils/global-refs";
|
||||
import { AppNavigationStack } from "./navigation-stack";
|
||||
import Orientation, {
|
||||
OrientationType,
|
||||
useDeviceOrientationChange
|
||||
} from "react-native-orientation-locker";
|
||||
|
||||
const MOBILE_SIDEBAR_SIZE = 0.85;
|
||||
|
||||
@@ -421,6 +421,7 @@ export const FluidPanelsView = React.memo(
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
backgroundColor: colors.primary.background,
|
||||
paddingBottom: Platform.OS === "android" ? insets?.bottom : 0,
|
||||
marginRight:
|
||||
orientation === "LANDSCAPE-RIGHT" && Platform.OS === "ios"
|
||||
? insets.right
|
||||
@@ -529,20 +530,17 @@ const onChangeTab = async (event: { i: number; from: number }) => {
|
||||
activateKeepAwake();
|
||||
eSendEvent(eOnEnterEditor);
|
||||
|
||||
if (
|
||||
useTabStore.getState().getTab(useTabStore.getState().currentTab)?.session
|
||||
?.locked
|
||||
) {
|
||||
eSendEvent(eUnlockNote);
|
||||
}
|
||||
|
||||
if (
|
||||
fluidTabsRef.current?.tabChangedFromSwipeAction.value &&
|
||||
!useTabStore.getState().getNoteIdForTab(useTabStore.getState().currentTab)
|
||||
) {
|
||||
editorController?.current?.commands?.focus(
|
||||
useTabStore.getState().currentTab
|
||||
);
|
||||
if (!useTabStore.getState().getCurrentNoteId()) {
|
||||
eSendEvent(eOnLoadNote, {
|
||||
newNote: true
|
||||
});
|
||||
} else {
|
||||
if (
|
||||
useTabStore.getState().getTab(useTabStore.getState().currentTab)
|
||||
?.session?.locked
|
||||
) {
|
||||
eSendEvent(eUnlockNote);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (event.from === 2) {
|
||||
|
||||
@@ -96,16 +96,14 @@ export const EditorWrapper = ({ widths }: { widths: any }) => {
|
||||
minHeight: "100%",
|
||||
backgroundColor: toolBarColors.primary.background,
|
||||
borderLeftWidth: DDS.isTab ? 1 : 0,
|
||||
borderLeftColor: DDS.isTab
|
||||
? colors.secondary.background
|
||||
: "transparent",
|
||||
paddingBottom: insets.bottom
|
||||
borderLeftColor: DDS.isTab ? colors.secondary.background : "transparent"
|
||||
}}
|
||||
>
|
||||
{loading || !introCompleted ? null : (
|
||||
<KeyboardAvoidingViewIOS
|
||||
behavior="padding"
|
||||
style={{
|
||||
marginBottom: getMarginBottom(),
|
||||
backgroundColor: colors.primary.background,
|
||||
flex: 1
|
||||
}}
|
||||
|
||||
@@ -113,10 +113,7 @@ async function onBackgroundSyncStarted() {
|
||||
useUserStore.getState().setSyncing(false);
|
||||
}
|
||||
await Notifications.setupReminders();
|
||||
if (SettingsService.get().notifNotes) {
|
||||
Notifications.pinQuickNote(false);
|
||||
}
|
||||
Notifications.restorePinnedNotes();
|
||||
|
||||
NotePreviewWidget.updateNotes();
|
||||
deleteDCacheFiles();
|
||||
DatabaseLogger.info("BACKGROUND SYNC COMPLETE");
|
||||
@@ -145,7 +142,6 @@ const onBoot = async () => {
|
||||
Notifications.pinQuickNote(false);
|
||||
}
|
||||
Notifications.restorePinnedNotes();
|
||||
NotePreviewWidget.updateNotes();
|
||||
DatabaseLogger.info("BOOT TASK COMPLETE");
|
||||
} catch (e) {
|
||||
DatabaseLogger.error(e as Error);
|
||||
|
||||
@@ -348,7 +348,7 @@ async function scheduleNotification(
|
||||
title: title,
|
||||
message: description || "",
|
||||
ongoing: true,
|
||||
// subtitle: description || "",
|
||||
subtitle: description || "",
|
||||
actions: [strings.unpin()]
|
||||
});
|
||||
}
|
||||
@@ -396,7 +396,7 @@ async function scheduleNotification(
|
||||
payload: payload || "",
|
||||
dateModified: reminder.dateModified + ""
|
||||
},
|
||||
// subtitle: !description ? undefined : description,
|
||||
subtitle: !description ? undefined : description,
|
||||
android: {
|
||||
channelId: await getChannelId(priority),
|
||||
smallIcon: "ic_stat_name",
|
||||
@@ -916,21 +916,8 @@ async function pinQuickNote(launch: boolean) {
|
||||
* A function that checks if reminders need to be reconfigured &
|
||||
* reschedules them if anything has changed.
|
||||
*/
|
||||
|
||||
async function setupReminders(checkNeedsScheduling = false) {
|
||||
const reminders = ((await db.reminders?.all.items()) as Reminder[]) || [];
|
||||
let notificationsCancelled = false;
|
||||
if (Platform.OS === "android") {
|
||||
// If the API level has changed, cancel all notifications.
|
||||
// This is to ensure that the app does not crash on Android 14+.
|
||||
const API_LEVEL = MMKV.getInt("android_apiLevel");
|
||||
if (API_LEVEL !== (Platform.Version as number)) {
|
||||
await notifee.cancelAllNotifications();
|
||||
notificationsCancelled = true;
|
||||
MMKV.setInt("android_apiLevel", Platform.Version as number);
|
||||
}
|
||||
}
|
||||
|
||||
const triggers = await notifee.getTriggerNotifications();
|
||||
for (const reminder of reminders) {
|
||||
if (reminder.mode === "permanent") {
|
||||
@@ -940,22 +927,20 @@ async function setupReminders(checkNeedsScheduling = false) {
|
||||
// Skip reminders that are not repeating and their trigger date is in past.
|
||||
if (reminder.mode === "once" && dayjs().isAfter(reminder.date)) continue;
|
||||
|
||||
if (!notificationsCancelled) {
|
||||
const pending = triggers.filter((t) =>
|
||||
t.notification.id?.startsWith(reminder.id)
|
||||
);
|
||||
const pending = triggers.filter((t) =>
|
||||
t.notification.id?.startsWith(reminder.id)
|
||||
);
|
||||
|
||||
let needsReschedule = pending.length === 0 ? true : false;
|
||||
if (!needsReschedule) {
|
||||
needsReschedule = pending[0].notification.data?.dateModified
|
||||
? parseInt(pending[0].notification.data?.dateModified as string) <
|
||||
reminder.dateModified
|
||||
: true;
|
||||
}
|
||||
|
||||
if (!needsReschedule && checkNeedsScheduling) continue;
|
||||
let needsReschedule = pending.length === 0 ? true : false;
|
||||
if (!needsReschedule) {
|
||||
needsReschedule = pending[0].notification.data?.dateModified
|
||||
? parseInt(pending[0].notification.data?.dateModified as string) <
|
||||
reminder.dateModified
|
||||
: true;
|
||||
}
|
||||
|
||||
if (!needsReschedule && checkNeedsScheduling) continue;
|
||||
|
||||
await scheduleNotification(reminder);
|
||||
}
|
||||
// Check for any triggers whose notifications
|
||||
|
||||
@@ -45,10 +45,10 @@ export function initAfterSync(type: "full" | "send" = "send") {
|
||||
useUserStore.setState({
|
||||
profile: db.settings.getProfile()
|
||||
});
|
||||
eSendEvent(eAfterSync);
|
||||
}
|
||||
Notifications.setupReminders(true);
|
||||
NotePreviewWidget.updateNotes();
|
||||
eSendEvent(eAfterSync);
|
||||
}
|
||||
|
||||
export async function initialize() {}
|
||||
|
||||
@@ -43,7 +43,7 @@ export function changeSystemBarColors() {
|
||||
const isDark = useThemeStore.getState().colorScheme === "dark";
|
||||
changeNavigationBarColor(
|
||||
currTheme.scopes.base.primary.background,
|
||||
!isDark,
|
||||
isDark,
|
||||
false
|
||||
);
|
||||
StatusBar.setBackgroundColor("transparent" as any);
|
||||
|
||||
@@ -40,7 +40,6 @@ interface NotesnookModuleInterface {
|
||||
hasWidgetNote: (noteId: string) => Promise<boolean>;
|
||||
updateWidgetNote: (noteId: string, data: string) => void;
|
||||
updateReminderWidget: () => void;
|
||||
isGestureNavigationEnabled: () => boolean;
|
||||
}
|
||||
|
||||
export const NotesnookModule: NotesnookModuleInterface = Platform.select({
|
||||
@@ -60,8 +59,7 @@ export const NotesnookModule: NotesnookModuleInterface = Platform.select({
|
||||
getWidgetNotes: () => {},
|
||||
hasWidgetNote: () => {},
|
||||
updateWidgetNote: () => {},
|
||||
updateReminderWidget: () => {},
|
||||
isGestureNavigationEnabled: () => true
|
||||
updateReminderWidget: () => {}
|
||||
},
|
||||
android: NativeModules.NNativeModule
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3066
|
||||
versionCode 3059
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -11,69 +11,57 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
tools:node="remove" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.USE_FULL_SCREEN_INTENT"
|
||||
tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" tools:node="remove" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="text/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="image/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="application/pdf" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="text/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="image/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
|
||||
<data android:mimeType="video/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="audio/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
<data android:mimeType="video/*" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- If you don't know the MIME type in advance, set "mimeType" to "*/*". -->
|
||||
<data android:mimeType="audio/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:theme="@style/BootTheme"
|
||||
android:largeHeap="true"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/BootTheme">
|
||||
|
||||
<receiver
|
||||
android:name=".NoteWidget"
|
||||
android:exported="false"
|
||||
android:label="@string/quick_note">
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
|
||||
<receiver android:exported="false" android:label="@string/quick_note" android:name=".NoteWidget">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -83,10 +71,7 @@
|
||||
android:resource="@xml/new_note_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".NotePreviewWidget"
|
||||
android:exported="false"
|
||||
android:label="@string/note">
|
||||
<receiver android:exported="false" android:label="@string/note" android:name=".NotePreviewWidget">
|
||||
<intent-filter>"
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -96,10 +81,7 @@
|
||||
android:resource="@xml/note_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".ReminderWidgetProvider"
|
||||
android:exported="false"
|
||||
android:label="@string/reminders_title">
|
||||
<receiver android:exported="false" android:label="@string/reminders_title" android:name=".ReminderWidgetProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
@@ -108,37 +90,33 @@
|
||||
android:resource="@xml/widget_reminders_info" />
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".NotePreviewConfigureActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:exported="true"
|
||||
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:label="NotePreviewConfigure"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustResize" android:name=".NotePreviewConfigureActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask"
|
||||
android:resizeableActivity="true"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="Notesnook">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
@@ -149,7 +127,6 @@
|
||||
|
||||
<intent-filter android:label="Notesnook">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
@@ -157,25 +134,22 @@
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.facebook.react.devsupport.DevSettingsActivity"
|
||||
android:exported="false" />
|
||||
<activity android:exported="false" android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
<activity
|
||||
android:name=".ShareActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_share"
|
||||
android:noHistory="true"
|
||||
android:screenOrientation="unspecified"
|
||||
android:exported="true"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/AppThemeB"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:excludeFromRecents="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:theme="@style/AppThemeB">
|
||||
|
||||
<intent-filter android:label="Make Note">
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
@@ -186,7 +160,6 @@
|
||||
<intent-filter android:label="Make Note">
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/*" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
@@ -206,41 +179,35 @@
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:stopWithTask="false" />
|
||||
<service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" />
|
||||
<service android:name="com.asterinet.react.bgactions.RNBackgroundActionsTask" />
|
||||
|
||||
<service
|
||||
android:name="com.streetwriters.notesnook.BootTaskService"
|
||||
android:foregroundServiceType="specialUse">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="The service is required by the app to restore notifications of pinned notes, restore notification with reply input for creating notes and restore data in note preview widgets on device reboot." />
|
||||
</service>
|
||||
<service android:name="com.streetwriters.notesnook.BootTaskService" android:foregroundServiceType="dataSync" />
|
||||
|
||||
<service
|
||||
android:name=".NotesnookTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/add_note"
|
||||
android:label="New note"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".ReminderViewsService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
<service
|
||||
android:name=".ReminderViewsService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="com.vinzscam.reactnativefileviewer.FileProvider"
|
||||
@@ -252,14 +219,12 @@
|
||||
android:resource="@xml/file_viewer_provider_paths" />
|
||||
</provider>
|
||||
|
||||
<receiver
|
||||
android:name=".BootRecieverService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:exported="true" android:name=".BootRecieverService">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class BootTaskService extends HeadlessJsTaskService {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
|
||||
"Default",
|
||||
@@ -54,7 +55,7 @@ public class BootTaskService extends HeadlessJsTaskService {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
|
||||
@@ -7,9 +7,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.RemoteViews;
|
||||
@@ -219,24 +217,4 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
|
||||
wm.notifyAppWidgetViewDataChanged(id, R.id.widget_list_view);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public boolean isGestureNavigationEnabled() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
try {
|
||||
String navBarMode = Settings.Secure.getString(
|
||||
mContext.getContentResolver(),
|
||||
"navigation_mode"
|
||||
);
|
||||
return "2".equals(navBarMode);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- Add scroll to top/bottom in editor
|
||||
- Fix toolbar hidden behing keyboard on android 15 and 16
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -5,5 +5,5 @@ rootProject.name = 'Notesnook'
|
||||
include ':app'
|
||||
includeBuild('../../node_modules/@react-native/gradle-plugin')
|
||||
|
||||
include ":lazysodium-android"
|
||||
project(':lazysodium-android').projectDir = new File(rootProject.projectDir, '../../node_modules/@ammarahmed/react-native-sodium/android/lazysodium-android/app')
|
||||
include ":lazysodium"
|
||||
project(':lazysodium').projectDir = new File(rootProject.projectDir, '../../node_modules/@ammarahmed/react-native-sodium/android/lazysodium')
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
6517B7C12B6838EB0079FF37 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6517B7BE2B6838EB0079FF37 /* OpenSans-Regular.ttf */; };
|
||||
6517B7C22B6838EB0079FF37 /* OpenSans-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6517B7BF2B6838EB0079FF37 /* OpenSans-SemiBold.ttf */; };
|
||||
6517B7C32B6838EB0079FF37 /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6517B7C02B6838EB0079FF37 /* OpenSans-Bold.ttf */; };
|
||||
651F09DA2E0D262B00495DED /* fts5-html.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 651F09D92E0D262B00495DED /* fts5-html.xcframework */; };
|
||||
651F09DB2E0D262B00495DED /* fts5-html.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 651F09D92E0D262B00495DED /* fts5-html.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
651F09DD2E0D263300495DED /* fts5-html.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 651F09D92E0D262B00495DED /* fts5-html.xcframework */; };
|
||||
6529A13E279BC4C70048D4A8 /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6529A13D279BC4C70048D4A8 /* BootSplash.storyboard */; };
|
||||
656835812BB29A9800144BAB /* OpenSans-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 656835802BB29A8300144BAB /* OpenSans-Italic.ttf */; };
|
||||
6569927F2C5754F10041CD41 /* OpenSans-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6517B7C02B6838EB0079FF37 /* OpenSans-Bold.ttf */; };
|
||||
@@ -79,6 +82,17 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
651F09DC2E0D262C00495DED /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
651F09DB2E0D262B00495DED /* fts5-html.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
65A7F34B255687E600699170 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -120,6 +134,7 @@
|
||||
6517B7BE2B6838EB0079FF37 /* OpenSans-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Regular.ttf"; path = "../../../../packages/editor-mobile/public/fonts/OpenSans-Regular.ttf"; sourceTree = "<group>"; };
|
||||
6517B7BF2B6838EB0079FF37 /* OpenSans-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-SemiBold.ttf"; path = "../../../../packages/editor-mobile/public/fonts/OpenSans-SemiBold.ttf"; sourceTree = "<group>"; };
|
||||
6517B7C02B6838EB0079FF37 /* OpenSans-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Bold.ttf"; path = "../../../../packages/editor-mobile/public/fonts/OpenSans-Bold.ttf"; sourceTree = "<group>"; };
|
||||
651F09D92E0D262B00495DED /* fts5-html.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = "fts5-html.xcframework"; sourceTree = "<group>"; };
|
||||
6529A13D279BC4C70048D4A8 /* BootSplash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = BootSplash.storyboard; path = Notesnook/BootSplash.storyboard; sourceTree = "<group>"; };
|
||||
6529D2B0257B4A2900B49BC3 /* NotesnookDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = NotesnookDebug.entitlements; path = Notesnook/NotesnookDebug.entitlements; sourceTree = "<group>"; };
|
||||
656835802BB29A8300144BAB /* OpenSans-Italic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "OpenSans-Italic.ttf"; path = "../../../../packages/editor-mobile/public/fonts/OpenSans-Italic.ttf"; sourceTree = "<group>"; };
|
||||
@@ -176,6 +191,7 @@
|
||||
files = (
|
||||
2B3F87EC6B2264CD8ABA5DA8 /* libPods-Notesnook.a in Frameworks */,
|
||||
6515C42F2580AA3000E83E39 /* StoreKit.framework in Frameworks */,
|
||||
651F09DA2E0D262B00495DED /* fts5-html.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -208,6 +224,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
651F09DD2E0D263300495DED /* fts5-html.xcframework in Frameworks */,
|
||||
C619D096A9DE2070DBEAC70F /* libPods-Make Note.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -255,6 +272,7 @@
|
||||
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
651F09D92E0D262B00495DED /* fts5-html.xcframework */,
|
||||
6515C42E2580AA2F00E83E39 /* StoreKit.framework */,
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
ED2971642150620600B7C4FE /* JavaScriptCore.framework */,
|
||||
@@ -398,6 +416,7 @@
|
||||
240525450DF9ABA0F332B52E /* [CP] Copy Pods Resources */,
|
||||
65A7F34B255687E600699170 /* Embed App Extensions */,
|
||||
48C834D962D612F18A0388B3 /* [CP] Embed Pods Frameworks */,
|
||||
651F09DC2E0D262C00495DED /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1089,7 +1108,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1163,7 +1182,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1194,7 +1213,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1268,7 +1287,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1427,7 +1446,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1439,7 +1458,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1470,7 +1489,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1483,7 +1502,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1513,16 +1532,10 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/universal\"",
|
||||
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built\"",
|
||||
"\"${PROJECT_DIR}\"",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -1593,8 +1606,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1625,17 +1637,11 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2145;
|
||||
CURRENT_PROJECT_VERSION = 2137;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/universal\"",
|
||||
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built\"",
|
||||
"\"${PROJECT_DIR}\"",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -1706,8 +1712,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.2.10;
|
||||
MARKETING_VERSION = 3.2.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1784,10 +1789,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
@@ -1852,10 +1854,7 @@
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
|
||||
@@ -1325,28 +1325,6 @@ PODS:
|
||||
- react-native-pdf (6.7.7):
|
||||
- React-Core
|
||||
- react-native-quick-sqlite (8.2.7):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2024.11.18.00)
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- react-native-quick-sqlite/lexbor (= 8.2.7)
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCodegen
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-quick-sqlite/lexbor (8.2.7):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
@@ -2431,7 +2409,7 @@ SPEC CHECKSUMS:
|
||||
react-native-orientation-locker: cc6f357b289a2e0dd2210fea0c52cb8e0727fdaa
|
||||
react-native-pager-view: 5aaf51a9338f7997b8acee0e0febfddd1ade5c0a
|
||||
react-native-pdf: 6a51a22ccefb23eb93298771e4bf090913e86d70
|
||||
react-native-quick-sqlite: 1bfc7f1e9acbe9a5aa5c4cc81712e9bde3ab7672
|
||||
react-native-quick-sqlite: d09ab51a1111d7713a2f38fe7805e021a74fe877
|
||||
react-native-safe-area-context: 9d72abf6d8473da73033b597090a80b709c0b2f1
|
||||
react-native-screenguard: 82437eeb0086a90b5e5d7e54130bb04fb406373e
|
||||
react-native-share-extension: bcb7e466390a9e50c742f4b1019d6f181aedd7ad
|
||||
|
||||
44
apps/mobile/native/ios/fts5-html.xcframework/Info.plist
Normal file
44
apps/mobile/native/ios/fts5-html.xcframework/Info.plist
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AvailableLibraries</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>fts5-html.dylib</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>fts5-html.dylib</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>BinaryPath</key>
|
||||
<string>fts5-html.dylib</string>
|
||||
<key>LibraryIdentifier</key>
|
||||
<string>ios-arm64_x86_64-simulator</string>
|
||||
<key>LibraryPath</key>
|
||||
<string>fts5-html.dylib</string>
|
||||
<key>SupportedArchitectures</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
<string>x86_64</string>
|
||||
</array>
|
||||
<key>SupportedPlatform</key>
|
||||
<string>ios</string>
|
||||
<key>SupportedPlatformVariant</key>
|
||||
<string>simulator</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XFWK</string>
|
||||
<key>XCFrameworkFormatVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
Binary file not shown.
@@ -66,7 +66,7 @@
|
||||
"react-native-screenguard": "^1.0.0",
|
||||
"@formatjs/intl-locale": "4.0.0",
|
||||
"@formatjs/intl-pluralrules": "5.2.14",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.5",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.4",
|
||||
"@react-native-community/datetimepicker": "^8.2.0",
|
||||
"react-native-exit-app": "github:ammarahm-ed/react-native-exit-app",
|
||||
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
|
||||
|
||||
337
apps/mobile/package-lock.json
generated
337
apps/mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.2.10",
|
||||
"version": "3.2.3",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -56,4 +56,4 @@
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.77.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
diff --git a/node_modules/react-native-actions-sheet/dist/src/index.js b/node_modules/react-native-actions-sheet/dist/src/index.js
|
||||
index 0e124da..3703153 100644
|
||||
--- a/node_modules/react-native-actions-sheet/dist/src/index.js
|
||||
+++ b/node_modules/react-native-actions-sheet/dist/src/index.js
|
||||
@@ -1088,6 +1088,7 @@ export default forwardRef(function ActionSheet(_a, ref) {
|
||||
* Always true, it causes issue with keyboard handling.
|
||||
*/
|
||||
statusBarTranslucent: true,
|
||||
+ navigationBarTranslucent: true
|
||||
}
|
||||
: {
|
||||
testID: ((_b = props.testIDs) === null || _b === void 0 ? void 0 : _b.root) || props.testID,
|
||||
@@ -36,37 +36,3 @@ index 3dfe1dc..70ef9da 100644
|
||||
+ implementation 'io.legere:pdfiumandroid:1.0.32'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
}
|
||||
diff --git a/node_modules/react-native-pdf/android/src/main/java/org/wonday/pdf/PdfView.java b/node_modules/react-native-pdf/android/src/main/java/org/wonday/pdf/PdfView.java
|
||||
index 7b7a125..361924b 100644
|
||||
--- a/node_modules/react-native-pdf/android/src/main/java/org/wonday/pdf/PdfView.java
|
||||
+++ b/node_modules/react-native-pdf/android/src/main/java/org/wonday/pdf/PdfView.java
|
||||
@@ -12,6 +12,8 @@ import java.io.File;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
+import android.os.Handler;
|
||||
+import android.os.Looper;
|
||||
import android.util.SizeF;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -105,7 +107,7 @@ public class PdfView extends PDFView implements OnPageChangeListener,OnLoadCompl
|
||||
TopChangeEvent tce = new TopChangeEvent(surfaceId, getId(), event);
|
||||
|
||||
if (dispatcher != null) {
|
||||
- dispatcher.dispatchEvent(tce);
|
||||
+ new Handler(Looper.getMainLooper()).postDelayed(() -> dispatcher.dispatchEvent(tce), 10);
|
||||
}
|
||||
|
||||
// ReactContext reactContext = (ReactContext)this.getContext();
|
||||
diff --git a/node_modules/react-native-pdf/index.js b/node_modules/react-native-pdf/index.js
|
||||
index 56df005..dd14412 100644
|
||||
--- a/node_modules/react-native-pdf/index.js
|
||||
+++ b/node_modules/react-native-pdf/index.js
|
||||
@@ -364,7 +364,6 @@ export default class Pdf extends Component {
|
||||
}
|
||||
|
||||
_onChange = (event) => {
|
||||
-
|
||||
let message = event.nativeEvent.message.split('|');
|
||||
//__DEV__ && console.log("onChange: " + message);
|
||||
if (message.length > 0) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -107,12 +107,10 @@ function generateTableOfContents() {
|
||||
|
||||
export const MonographPage = ({
|
||||
monograph,
|
||||
encodedKey,
|
||||
apiHost
|
||||
encodedKey
|
||||
}: {
|
||||
monograph: Monograph;
|
||||
encodedKey?: string;
|
||||
apiHost: string;
|
||||
}) => {
|
||||
const [reportDialogVisible, setReportDialogVisible] = useState(false);
|
||||
const [tableOfContents, setTableOfContents] = useState<TableOfContent[]>([]);
|
||||
@@ -229,7 +227,7 @@ export const MonographPage = ({
|
||||
)}
|
||||
<Image
|
||||
sx={{ display: "none" }}
|
||||
src={`${apiHost}/monographs/${monograph.id}/view`}
|
||||
src={`https://api.notesnook.com/monographs/${monograph.id}/view`}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
@@ -85,8 +85,7 @@ export async function loader({ params }: LoaderFunctionArgs) {
|
||||
const metadata = getMonographMetadata(monograph);
|
||||
return {
|
||||
monograph,
|
||||
metadata,
|
||||
apiHost: API_HOST
|
||||
metadata
|
||||
};
|
||||
} catch (e) {
|
||||
// console.error(e);
|
||||
@@ -97,24 +96,19 @@ export async function loader({ params }: LoaderFunctionArgs) {
|
||||
fullDescription: "This monograph does not exist.",
|
||||
shortDescription: "This monograph does not exist.",
|
||||
datePublished: ""
|
||||
},
|
||||
apiHost: API_HOST
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default function MonographPost() {
|
||||
const { monograph, apiHost } = useLoaderData<typeof loader>();
|
||||
const { monograph } = useLoaderData<typeof loader>();
|
||||
const [_, hashParams] = useHashLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
{monograph ? (
|
||||
<MonographPage
|
||||
monograph={monograph}
|
||||
encodedKey={hashParams.key}
|
||||
apiHost={apiHost}
|
||||
/>
|
||||
<MonographPage monograph={monograph} encodedKey={hashParams.key} />
|
||||
) : (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
4
apps/theme-builder/package-lock.json
generated
4
apps/theme-builder/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/theme-builder",
|
||||
"version": "1.4.0",
|
||||
"version": "1.3.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/theme-builder",
|
||||
"version": "1.4.0",
|
||||
"version": "1.3.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@emotion/react": "11.11.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/theme-builder",
|
||||
"description": "Your private note taking space",
|
||||
"version": "1.4.0",
|
||||
"version": "1.3.0",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||
@@ -1 +1 @@
|
||||
An edit I madeThis is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1An edit I made
|
||||
@@ -1 +1 @@
|
||||
An edit I madeThis is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1An edit I made
|
||||
@@ -1 +1 @@
|
||||
An edit I madeThis is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1An edit I made
|
||||
@@ -162,9 +162,9 @@ export class SettingsViewModel {
|
||||
|
||||
await appLockSwitch.click();
|
||||
await fillPasswordDialog(this.page, userPassword);
|
||||
await this.page.waitForTimeout(500);
|
||||
await this.page.waitForTimeout(100);
|
||||
await fillConfirmPasswordDialog(this.page, appLockPassword);
|
||||
await this.page.waitForTimeout(500);
|
||||
await this.page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
async disableAppLock(appLockPassword: string) {
|
||||
|
||||
@@ -91,7 +91,6 @@ export async function fillReminderDialog(
|
||||
}
|
||||
|
||||
await confirmDialog(dialog);
|
||||
await dialog.waitFor({ state: "hidden" });
|
||||
}
|
||||
|
||||
export async function fillItemDialog(page: Page, item: Item) {
|
||||
@@ -134,6 +133,7 @@ export async function fillConfirmPasswordDialog(page: Page, password: string) {
|
||||
export async function confirmDialog(dialog: Locator) {
|
||||
const dialogConfirm = dialog.locator(getTestId("dialog-yes"));
|
||||
await dialogConfirm.click();
|
||||
// await dialogConfirm.waitFor({ state: "detached" });
|
||||
}
|
||||
|
||||
export async function denyDialog(page: Page) {
|
||||
|
||||
@@ -53,17 +53,16 @@ test("adding a one-time reminder before current time should not be possible", as
|
||||
await app.goto();
|
||||
const reminders = await app.goToReminders();
|
||||
|
||||
const result = await Promise.race([
|
||||
reminders.createReminder({
|
||||
...ONE_TIME_REMINDER,
|
||||
date: 0
|
||||
}),
|
||||
app.toasts.waitForToast(
|
||||
await reminders.createReminder({
|
||||
...ONE_TIME_REMINDER,
|
||||
date: 0
|
||||
});
|
||||
|
||||
expect(
|
||||
await app.toasts.waitForToast(
|
||||
"Reminder time cannot be earlier than the current time."
|
||||
)
|
||||
]);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
for (const recurringMode of ["Daily", "Weekly", "Monthly"] as const) {
|
||||
|
||||
@@ -455,7 +455,6 @@ test("if note is active in multiple tabs, moving the note to trash should close
|
||||
title: "Note 1"
|
||||
});
|
||||
await note?.contextMenu.openInNewTab();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await note?.contextMenu.moveToTrash();
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ kbd {
|
||||
background: var(--background);
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
color: var(--paragraph);
|
||||
color: var(--paragraph-secondary);
|
||||
}
|
||||
|
||||
.ping {
|
||||
|
||||
@@ -60,14 +60,6 @@ function App() {
|
||||
useSettingStore.getState().desktopIntegrationSettings?.nativeTitlebar;
|
||||
console.timeEnd("loading app");
|
||||
|
||||
useEffect(() => {
|
||||
if (isMobile) {
|
||||
useStore.setState({
|
||||
isNavPaneCollapsed: false
|
||||
});
|
||||
}
|
||||
}, [isMobile]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isFocused ? null : (
|
||||
|
||||
@@ -53,8 +53,7 @@ import { MenuItem } from "@notesnook/ui";
|
||||
export const CREATE_BUTTON_MAP = {
|
||||
notes: {
|
||||
title: strings.addItem("note"),
|
||||
onClick: () => useEditorStore.getState().newSession(),
|
||||
onAuxClick: () => useEditorStore.getState().addTab()
|
||||
onClick: () => useEditorStore.getState().newSession()
|
||||
},
|
||||
notebooks: {
|
||||
title: strings.addItem("notebook"),
|
||||
|
||||
@@ -23,9 +23,6 @@ import { useStore as useSearchStore } from "../stores/search-store";
|
||||
import { useEditorManager } from "../components/editor/manager";
|
||||
import { CommandPaletteDialog } from "../dialogs/command-palette";
|
||||
import { hashNavigate } from "../navigation";
|
||||
import { getKeybinding, keybindings } from "@notesnook/common";
|
||||
import { KeyboardShortcutsDialog } from "../dialogs/keyboard-shortcuts-dialog";
|
||||
import { isMac } from "../utils/platform";
|
||||
|
||||
function isInEditor(e: KeyboardEvent) {
|
||||
return (
|
||||
@@ -33,71 +30,200 @@ function isInEditor(e: KeyboardEvent) {
|
||||
);
|
||||
}
|
||||
|
||||
const actions: Partial<
|
||||
Record<keyof typeof keybindings, (() => void) | ((e: KeyboardEvent) => void)>
|
||||
> = {
|
||||
nextTab: () => useEditorStore.getState().focusNextTab(),
|
||||
previousTab: () => useEditorStore.getState().focusPreviousTab(),
|
||||
newTab: () => useEditorStore.getState().addTab(),
|
||||
newNote: () => useEditorStore.getState().newSession(),
|
||||
closeActiveTab: () => {
|
||||
const activeTab = useEditorStore.getState().getActiveTab();
|
||||
if (activeTab?.pinned) {
|
||||
useEditorStore.getState().focusLastActiveTab();
|
||||
return;
|
||||
}
|
||||
useEditorStore.getState().closeActiveTab();
|
||||
const KEYMAP = [
|
||||
// {
|
||||
// keys: ["command+n", "ctrl+n", "command+alt+n", "ctrl+alt+n"],
|
||||
// description: "Create a new note",
|
||||
// global: true,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// hashNavigate("/notes/create", {
|
||||
// addNonce: true,
|
||||
// replace: true,
|
||||
// notify: true,
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: [
|
||||
// "command+shift+n",
|
||||
// "ctrl+shift+n",
|
||||
// "command+shift+alt+n",
|
||||
// "ctrl+shift+alt+n",
|
||||
// ],
|
||||
// description: "Create a new notebook",
|
||||
// global: true,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// hashNavigate("/notebooks/create", {
|
||||
// replace: true,
|
||||
// notify: true,
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
{
|
||||
keys: [
|
||||
"command+option+right",
|
||||
"ctrl+alt+right",
|
||||
"command+option+shift+right",
|
||||
"ctrl+alt+shift+right",
|
||||
"ctrl+tab",
|
||||
"command+tab"
|
||||
],
|
||||
description: "Go to next tab",
|
||||
action: () => useEditorStore.getState().focusNextTab()
|
||||
},
|
||||
closeAllTabs: () => useEditorStore.getState().closeAllTabs(),
|
||||
searchInNotes: (e: KeyboardEvent) => {
|
||||
if (isInEditor(e)) {
|
||||
const activeSession = useEditorStore.getState().getActiveSession();
|
||||
if (activeSession?.type === "readonly") {
|
||||
e.preventDefault();
|
||||
const editor = useEditorManager.getState().getEditor(activeSession.id);
|
||||
editor?.editor?.startSearch();
|
||||
{
|
||||
keys: [
|
||||
"command+option+left",
|
||||
"ctrl+alt+left",
|
||||
"command+option+shift+left",
|
||||
"ctrl+alt+shift+left",
|
||||
"ctrl+shift+tab",
|
||||
"command+shift+tab"
|
||||
],
|
||||
description: "Go to previous tab",
|
||||
action: () => useEditorStore.getState().focusPreviousTab()
|
||||
},
|
||||
{
|
||||
keys: ["ctrl+t", "command+t"],
|
||||
description: "Create a new tab",
|
||||
action: () => useEditorStore.getState().addTab()
|
||||
},
|
||||
{
|
||||
keys: ["ctrl+n", "command+n"],
|
||||
description: "Create a new note",
|
||||
action: () => useEditorStore.getState().newSession()
|
||||
},
|
||||
{
|
||||
keys: ["ctrl+w", "command+w"],
|
||||
description:
|
||||
"Close active tab or focus previously activated tab if active tab pinned",
|
||||
action: () => {
|
||||
const activeTab = useEditorStore.getState().getActiveTab();
|
||||
if (activeTab?.pinned) {
|
||||
useEditorStore.getState().focusLastActiveTab();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
useEditorStore.getState().closeActiveTab();
|
||||
}
|
||||
e.preventDefault();
|
||||
},
|
||||
{
|
||||
keys: ["ctrl+shift+w", "command+shift+w"],
|
||||
description: "Close all tabs",
|
||||
action: () => useEditorStore.getState().closeAllTabs()
|
||||
},
|
||||
{
|
||||
keys: ["command+f", "ctrl+f"],
|
||||
description: "Search all notes",
|
||||
global: false,
|
||||
action: (e: KeyboardEvent) => {
|
||||
if (isInEditor(e)) {
|
||||
const activeSession = useEditorStore.getState().getActiveSession();
|
||||
if (activeSession?.type === "readonly") {
|
||||
e.preventDefault();
|
||||
const editor = useEditorManager
|
||||
.getState()
|
||||
.getEditor(activeSession.id);
|
||||
editor?.editor?.startSearch();
|
||||
}
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
useSearchStore.setState({ isSearching: true, searchType: "notes" });
|
||||
useSearchStore.setState({ isSearching: true, searchType: "notes" });
|
||||
}
|
||||
},
|
||||
openCommandPalette: () => {
|
||||
CommandPaletteDialog.close();
|
||||
CommandPaletteDialog.show({
|
||||
isCommandMode: true
|
||||
}).catch(() => {});
|
||||
// {
|
||||
// keys: ["alt+n"],
|
||||
// description: "Go to Notes",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/notes");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["alt+b"],
|
||||
// description: "Go to Notebooks",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/notebooks");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["alt+f"],
|
||||
// description: "Go to Favorites",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/favorites");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["alt+t"],
|
||||
// description: "Go to Tags",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/tags");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["alt+d"],
|
||||
// description: "Go to Trash",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/trash");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["alt+s"],
|
||||
// description: "Go to Settings",
|
||||
// global: false,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// navigate("/settings");
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// keys: ["command+d", "ctrl+d"],
|
||||
// description: "Toggle dark/light mode",
|
||||
// global: true,
|
||||
// action: (e) => {
|
||||
// e.preventDefault();
|
||||
// themestore.get().toggleNightMode();
|
||||
// },
|
||||
// },
|
||||
{
|
||||
keys: ["ctrl+k", "cmd+k", "ctrl+p", "cmd+p"],
|
||||
description: "Open command palette",
|
||||
action: (e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
CommandPaletteDialog.close();
|
||||
CommandPaletteDialog.show({
|
||||
isCommandMode: e.key === "k"
|
||||
}).catch(() => {});
|
||||
}
|
||||
},
|
||||
openQuickOpen: () => {
|
||||
CommandPaletteDialog.close();
|
||||
CommandPaletteDialog.show({
|
||||
isCommandMode: false
|
||||
}).catch(() => {});
|
||||
},
|
||||
openSettings: (e) => {
|
||||
if (isInEditor(e)) return;
|
||||
hashNavigate("/settings", { replace: true });
|
||||
},
|
||||
openKeyboardShortcuts: () => KeyboardShortcutsDialog.show({})
|
||||
};
|
||||
{
|
||||
keys: ["ctrl+,", "command+,"],
|
||||
description: "Open settings",
|
||||
action: () => hashNavigate("/settings", { replace: true })
|
||||
}
|
||||
];
|
||||
|
||||
export function registerKeyMap() {
|
||||
hotkeys.filter = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
Object.entries(actions).forEach(([id, action]) => {
|
||||
const keys = getKeybinding(
|
||||
id as keyof typeof keybindings,
|
||||
IS_DESKTOP_APP,
|
||||
isMac()
|
||||
);
|
||||
if (!keys || keys.length === 0) return;
|
||||
|
||||
hotkeys(keys.join(","), (e) => {
|
||||
KEYMAP.forEach((key) => {
|
||||
hotkeys(key.keys.join(","), (e) => {
|
||||
e.preventDefault();
|
||||
action(e);
|
||||
key.action?.(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,10 +46,7 @@ export function ProviderSelector(props: ProviderSelectorProps) {
|
||||
sx={{ mt: 1, color: "paragraph", whiteSpace: "pre-wrap" }}
|
||||
>
|
||||
Can't find your notes app in the list?{" "}
|
||||
<a
|
||||
href="https://github.com/streetwriters/notesnook-importer/issues/new"
|
||||
target="_blank"
|
||||
>
|
||||
<a href="https://github.com/streetwriters/notesnook-importer/issues/new">
|
||||
Send us a request.
|
||||
</a>
|
||||
</Text>
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { PropsWithChildren, useEffect, useRef } from "react";
|
||||
import { Box } from "@theme-ui/components";
|
||||
import { Close, AddReminder, Menu } from "../icons";
|
||||
import { Close, AddReminder } from "../icons";
|
||||
import { useStore as useSearchStore } from "../../stores/search-store";
|
||||
import useMobile from "../../hooks/use-mobile";
|
||||
import { debounce, usePromise } from "@notesnook/common";
|
||||
@@ -27,7 +27,6 @@ import Field from "../field";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { RouteResult } from "../../navigation/types";
|
||||
import { CREATE_BUTTON_MAP } from "../../common";
|
||||
import { AppEventManager, AppEvents } from "../../common/app-events";
|
||||
|
||||
export type RouteContainerButtons = {
|
||||
search?: {
|
||||
@@ -134,16 +133,6 @@ function Header(props: RouteContainerProps) {
|
||||
if (e.key === "Escape") useSearchStore.getState().resetSearch();
|
||||
else useSearchStore.setState({ isSearching: true, searchType: type });
|
||||
}}
|
||||
leftActions={[
|
||||
{
|
||||
icon: Menu,
|
||||
hidden: !isMobile,
|
||||
id: "hamburger-menu",
|
||||
onClick: () => {
|
||||
AppEventManager.publish(AppEvents.toggleSideMenu, true);
|
||||
}
|
||||
}
|
||||
]}
|
||||
rightActions={[
|
||||
{
|
||||
icon: Close,
|
||||
|
||||
@@ -17,12 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
debounce,
|
||||
formatKey,
|
||||
keybindings,
|
||||
usePromise
|
||||
} from "@notesnook/common";
|
||||
import { debounce, usePromise } from "@notesnook/common";
|
||||
import { EVENTS, fuzzy, Note, Notebook, Reminder, Tag } from "@notesnook/core";
|
||||
import { Box, Button, Flex, Input, Text } from "@theme-ui/components";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
@@ -544,10 +539,7 @@ function getCommandPaletteHelp(isCommandMode: boolean) {
|
||||
...(isCommandMode
|
||||
? [
|
||||
{
|
||||
key: keybindings.openQuickOpen
|
||||
.keys(IS_DESKTOP_APP)
|
||||
.map((k) => formatKey(k, isMac(), "+"))
|
||||
.join(" / "),
|
||||
key: isMac() ? "⌘P" : "Ctrl+P",
|
||||
description: strings.quickOpen()
|
||||
}
|
||||
]
|
||||
@@ -561,10 +553,7 @@ function getCommandPaletteHelp(isCommandMode: boolean) {
|
||||
description: strings.createNewNote()
|
||||
},
|
||||
{
|
||||
key: keybindings.openCommandPalette
|
||||
.keys(IS_DESKTOP_APP)
|
||||
.map((k) => formatKey(k, isMac(), "+"))
|
||||
.join(" / "),
|
||||
key: isMac() ? "⌘K" : "Ctrl+K",
|
||||
description: strings.commandPalette()
|
||||
}
|
||||
])
|
||||
|
||||
@@ -50,7 +50,6 @@ import { notebookMenuItems } from "../../components/notebook";
|
||||
import { tagMenuItems } from "../../components/tag";
|
||||
import { useEditorManager } from "../../components/editor/manager";
|
||||
import Config from "../../utils/config";
|
||||
import { KeyboardShortcutsDialog } from "../keyboard-shortcuts-dialog";
|
||||
|
||||
export interface BaseCommand {
|
||||
id: string;
|
||||
@@ -182,14 +181,6 @@ const staticCommands: Command[] = [
|
||||
group: strings.navigate(),
|
||||
type: "command"
|
||||
},
|
||||
{
|
||||
id: "keyboard-shortcuts",
|
||||
title: "Keyboard shortcuts",
|
||||
icon: ArrowTopRight,
|
||||
action: () => KeyboardShortcutsDialog.show({}),
|
||||
group: strings.navigate(),
|
||||
type: "command"
|
||||
},
|
||||
{
|
||||
id: "attachment-manager",
|
||||
title: strings.attachmentManager(),
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { formatKey, getGroupedKeybindings } from "@notesnook/common";
|
||||
import { Flex, Text } from "@theme-ui/components";
|
||||
import { DialogManager } from "../common/dialog-manager";
|
||||
import Dialog from "../components/dialog";
|
||||
import { isMac } from "../utils/platform";
|
||||
|
||||
const groupedKeybindings = getGroupedKeybindings(IS_DESKTOP_APP, isMac());
|
||||
|
||||
export const KeyboardShortcutsDialog = DialogManager.register(
|
||||
function KeyboardShortcutsDialog(props) {
|
||||
return (
|
||||
<Dialog
|
||||
isOpen={true}
|
||||
title={"Keyboard Shortcuts"}
|
||||
width={750}
|
||||
onClose={() => props.onClose(false)}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
flexWrap: "nowrap",
|
||||
mt: 2,
|
||||
gap: 1
|
||||
}}
|
||||
>
|
||||
{groupedKeybindings.map((group) => {
|
||||
return (
|
||||
<Flex key={group.category} sx={{ flexDirection: "column" }}>
|
||||
<Text
|
||||
variant="subtitle"
|
||||
sx={{
|
||||
borderBottom: "1px solid var(--border)",
|
||||
mb: 1,
|
||||
pb: 1
|
||||
}}
|
||||
>
|
||||
{group.category}
|
||||
</Text>
|
||||
{group.shortcuts.map((shortcut) => {
|
||||
return (
|
||||
<Flex
|
||||
key={shortcut.description}
|
||||
sx={{
|
||||
mb: 2,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between"
|
||||
}}
|
||||
>
|
||||
<Text variant="body">{shortcut.description}</Text>
|
||||
<Keys keys={shortcut.keys} />
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
</Flex>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function Keys({ keys }: { keys: string[] }) {
|
||||
return (
|
||||
<Flex sx={{ gap: 1 }}>
|
||||
{keys.map((key, index) => (
|
||||
<>
|
||||
{key.split(" ").map((k) => (
|
||||
<Text
|
||||
key={k}
|
||||
as="code"
|
||||
sx={{
|
||||
bg: "background",
|
||||
color: "paragraph",
|
||||
px: 1,
|
||||
borderRadius: 5,
|
||||
fontSize: "body",
|
||||
border: "1px solid var(--border)"
|
||||
}}
|
||||
>
|
||||
{formatKey(k, isMac())}
|
||||
</Text>
|
||||
))}
|
||||
{keys.length - 1 !== index && (
|
||||
<Text as="span" sx={{ fontSize: "0.8em" }}>
|
||||
/
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -27,15 +27,15 @@ import {
|
||||
VirtualizedGrouping,
|
||||
createInternalLink
|
||||
} from "@notesnook/core";
|
||||
import { VirtualizedList } from "../components/virtualized-list";
|
||||
import { Button, Flex, Text } from "@theme-ui/components";
|
||||
import { ScrollContainer } from "@notesnook/ui";
|
||||
import { LinkAttributes } from "@notesnook/editor";
|
||||
import { NoteResolvedData, ResolvedItem } from "@notesnook/common";
|
||||
import { Lock } from "../components/icons";
|
||||
import { ellipsize } from "@notesnook/core";
|
||||
import { BaseDialogProps, DialogManager } from "../common/dialog-manager";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { CustomScrollbarsVirtualList } from "../components/list-container";
|
||||
|
||||
export type NoteLinkingDialogProps = BaseDialogProps<LinkAttributes | false> & {
|
||||
attributes?: LinkAttributes;
|
||||
@@ -83,10 +83,7 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
}}
|
||||
noScroll
|
||||
>
|
||||
<Flex
|
||||
variant="columnFill"
|
||||
sx={{ mx: 3, overflow: "hidden", height: 500 }}
|
||||
>
|
||||
<Flex variant="columnFill" sx={{ mx: 3, overflow: "hidden" }}>
|
||||
{selectedNote ? (
|
||||
<>
|
||||
<Field
|
||||
@@ -134,15 +131,15 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
{strings.noBlocksOnNote()}
|
||||
</Text>
|
||||
) : null}
|
||||
<Virtuoso
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
components={{
|
||||
Scroller: CustomScrollbarsVirtualList
|
||||
}}
|
||||
data={filteredBlocks || blocks}
|
||||
context={{ items: filteredBlocks || blocks }}
|
||||
itemContent={(_, item) => {
|
||||
return (
|
||||
<ScrollContainer>
|
||||
<VirtualizedList
|
||||
items={filteredBlocks || blocks}
|
||||
estimatedSize={34}
|
||||
mode="dynamic"
|
||||
itemGap={5}
|
||||
getItemKey={(i) => blocks[i].id}
|
||||
mt={1}
|
||||
renderItem={({ item }) => (
|
||||
<Button
|
||||
variant="menuitem"
|
||||
sx={{
|
||||
@@ -165,10 +162,7 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
>
|
||||
<Text
|
||||
variant="body"
|
||||
sx={{
|
||||
fontFamily: "monospace",
|
||||
whiteSpace: "pre-wrap"
|
||||
}}
|
||||
sx={{ fontFamily: "monospace", whiteSpace: "pre-wrap" }}
|
||||
>
|
||||
{ellipsize(item.content, 200, "end").trim() ||
|
||||
strings.linkNoteEmptyBlock()}
|
||||
@@ -187,9 +181,9 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
{item.type.toUpperCase()}
|
||||
</Text>
|
||||
</Button>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</ScrollContainer>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -209,14 +203,14 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
}}
|
||||
/>
|
||||
{notes && (
|
||||
<Virtuoso
|
||||
data={notes.placeholders}
|
||||
components={{
|
||||
Scroller: CustomScrollbarsVirtualList
|
||||
}}
|
||||
style={{ height: "100%", width: "100%" }}
|
||||
itemContent={(index) => (
|
||||
<div style={{ height: 28 }}>
|
||||
<ScrollContainer>
|
||||
<VirtualizedList
|
||||
items={notes.placeholders}
|
||||
estimatedSize={28}
|
||||
itemGap={5}
|
||||
getItemKey={notes.key}
|
||||
mt={1}
|
||||
renderItem={({ index }) => (
|
||||
<ResolvedItem items={notes} index={index} type="note">
|
||||
{({ item: note, data }) => (
|
||||
<Button
|
||||
@@ -245,9 +239,9 @@ export const NoteLinkingDialog = DialogManager.register(
|
||||
</Button>
|
||||
)}
|
||||
</ResolvedItem>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</ScrollContainer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -680,8 +680,7 @@ type ResolvedGroup = {
|
||||
};
|
||||
function getGroup(items: TreeNode[], groupId: string): ResolvedGroup | null {
|
||||
const index = items.findIndex((item) => item.id === groupId);
|
||||
const group = items.at(index);
|
||||
if (!group) return null;
|
||||
const group = items[index];
|
||||
if (!isGroup(group) && !isSubgroup(group)) return null;
|
||||
|
||||
const nextGroupIndex = items.findIndex(
|
||||
|
||||
@@ -31,7 +31,6 @@ import { SpellCheckerLanguages } from "./components/spell-checker-languages";
|
||||
import { CustomizeToolbar } from "./components/customize-toolbar";
|
||||
import { DictionaryWords } from "./components/dictionary-words";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { isMac } from "../../utils/platform";
|
||||
|
||||
export const EditorSettings: SettingsGroup[] = [
|
||||
{
|
||||
@@ -165,7 +164,7 @@ export const EditorSettings: SettingsGroup[] = [
|
||||
key: "spell-checker-languages",
|
||||
title: strings.languages(),
|
||||
description: strings.spellCheckerLanguagesDescription(),
|
||||
isHidden: () => !useSpellChecker.getState().enabled || isMac(),
|
||||
isHidden: () => !useSpellChecker.getState().enabled,
|
||||
onStateChange: (listener) =>
|
||||
useSpellChecker.subscribe((c) => c.enabled, listener),
|
||||
components: [
|
||||
|
||||
@@ -492,7 +492,6 @@ function SessionExpiry(props: BaseAuthComponentProps<"sessionExpiry">) {
|
||||
placeholder={user ? maskEmail(user.email) : undefined}
|
||||
autoFocus
|
||||
disabled
|
||||
required={false}
|
||||
/>
|
||||
<Button
|
||||
data-test-id="auth-forgot-password"
|
||||
@@ -975,10 +974,10 @@ function SubtitleWithAction(props: SubtitleWithActionProps) {
|
||||
export function AuthField(props: FieldProps) {
|
||||
return (
|
||||
<Field
|
||||
required
|
||||
{...props}
|
||||
name={props.name || props.id}
|
||||
data-test-id={props["data-test-id"] || props.id}
|
||||
required
|
||||
sx={{ mt: 2, width: "100%" }}
|
||||
styles={{
|
||||
// label: { fontWeight: "normal" },
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: OneNote
|
||||
---
|
||||
|
||||
# How do I import notes from OneNote notes app?
|
||||
|
||||
The following steps will help you import your notes from OneNote easily.
|
||||
|
||||
1. Go to [https://importer.notesnook.com/](https://importer.notesnook.com/) and select `OneNote` from list of apps.
|
||||

|
||||
2. Click on `Start importing`
|
||||

|
||||
3. Login to your account
|
||||

|
||||
4. Give permission to Notesnook Importer to access your notes
|
||||

|
||||
5. Wait while Notesnook importer imports your notes from OneNote account. Once importer completes processing, download the .zip file.
|
||||

|
||||
6. After you have downloaded the `.zip` file, [go to the Notesnook Web App](https://app.notesnook.com/) > Settings > Notesnook Importer. Select the .zip you downloaded earlier and click "Start import" button.
|
||||

|
||||
7. Once importing completes you should see all your notes in Notesnook. If you face any issues during importing, feel free to [report them on GitHub](https://github.com/streetwriters/notesnook-importer).
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: Standard Notes
|
||||
---
|
||||
|
||||
# How do I import notes from Standard Notes?
|
||||
|
||||
The following steps will help you import your notes from Standard notes easily.
|
||||
|
||||
1. Open Standard Notes app on Desktop or visit [https://app.standardnotes.org](https://app.standardnotes.org) and Login to your account.
|
||||
2. Click on `Preferences` icon on bottom left corner to open preferences.
|
||||

|
||||
3. Scroll down to `Data backups` section and choose backup type `Decrypted`.
|
||||

|
||||
4. Go to `Backups` from the Sidebar & select "Data backup" to download backup .zip file.
|
||||
5. Open the Notesnook app (web or desktop)
|
||||
6. Go to `Settings > Notesnook Importer` and select `Standard Notes` from list of apps.
|
||||

|
||||
7. Drop the .zip backup file you exported earlier from Standard Notes in the box or click anywhere to open system file picker to select the backup.
|
||||

|
||||
8. Once importing completes you should see all your notes in Notesnook. If you face any issues during importing, [report it on github](https://github.com/streetwriters/notesnook).
|
||||
@@ -1,78 +0,0 @@
|
||||
---
|
||||
title: Keyboard Shortcuts
|
||||
description: Keyboard shortcuts for Notesnook
|
||||
---
|
||||
|
||||
# Keyboard shortcuts
|
||||
|
||||
The following keyboard shortcuts will help you navigate Notesnook faster.
|
||||
|
||||
### General
|
||||
|
||||
| Description | Web | Windows/Linux | Mac |
|
||||
| --- | --- | --- | --- |
|
||||
| Search in notes list view if editor is not focused | Ctrl F | Ctrl F | ⌘ F |
|
||||
| Settings | Ctrl , | Ctrl , | ⌘ , |
|
||||
| Keyboard shortcuts | Ctrl / | Ctrl / | ⌘ / |
|
||||
| New note | - | Ctrl N | ⌘ N |
|
||||
|
||||
### Navigation
|
||||
|
||||
| Description | Web | Windows/Linux | Mac |
|
||||
| --- | --- | --- | --- |
|
||||
| Next tab | Ctrl Alt → / Ctrl Alt ⇧ → | Ctrl tab | ⌘ tab |
|
||||
| Previous tab | Ctrl Alt ← / Ctrl Alt ⇧ ← | Ctrl ⇧ tab | ⌘ ⇧ tab |
|
||||
| Command palette | Ctrl ⇧ P | Ctrl ⇧ P | ⌘ ⇧ P |
|
||||
| Quick open | Ctrl P | Ctrl P | ⌘ P |
|
||||
| New tab | - | Ctrl T | ⌘ T |
|
||||
| Close active tab | - | Ctrl W | ⌘ W |
|
||||
| Close all tabs | - | Ctrl ⇧ W | ⌘ ⇧ W |
|
||||
|
||||
### Editor
|
||||
|
||||
| Description | Web | Windows/Linux | Mac |
|
||||
| --- | --- | --- | --- |
|
||||
| Add attachment | Ctrl ⇧ A | Ctrl ⇧ A | ⌘ ⇧ A |
|
||||
| Insert blockquote | Ctrl ⇧ B | Ctrl ⇧ B | ⌘ ⇧ B |
|
||||
| Toggle bold | Ctrl B | Ctrl B | ⌘ B |
|
||||
| Toggle bullet list | Ctrl ⇧ 8 | Ctrl ⇧ 8 | ⌘ ⇧ 8 |
|
||||
| Toggle check list | Ctrl ⇧ 9 | Ctrl ⇧ 9 | ⌘ ⇧ 9 |
|
||||
| Split list item | ↵ | ↵ | ↵ |
|
||||
| Lift list item | ⇧ Tab | ⇧ Tab | ⇧ Tab |
|
||||
| Sink list item | Ctrl ⇧ Down | Ctrl ⇧ Down | ⌘ ⇧ Down |
|
||||
| Toggle code | Ctrl E | Ctrl E | ⌘ E |
|
||||
| Toggle code block | Ctrl ⇧ C | Ctrl ⇧ C | ⌘ ⇧ C |
|
||||
| Insert date | Alt D | Alt D | ⌥ D |
|
||||
| Insert time | Alt T | Alt T | ⌥ T |
|
||||
| Insert date and time | Ctrl Alt D | Ctrl Alt D | ⌘ ⌥ D |
|
||||
| Insert date and time with timezone | Ctrl Alt Z | Ctrl Alt Z | ⌘ ⌥ Z |
|
||||
| Increase font size | Ctrl [ | Ctrl [ | ⌘ [ |
|
||||
| Decrease font size | Ctrl ] | Ctrl ] | ⌘ ] |
|
||||
| Insert paragraph | Ctrl ⇧ 0 | Ctrl ⇧ 0 | ⌘ ⇧ 0 |
|
||||
| Insert heading 1 | Ctrl Alt 1 | Ctrl Alt 1 | ⌘ ⌥ 1 |
|
||||
| Insert heading 2 | Ctrl Alt 2 | Ctrl Alt 2 | ⌘ ⌥ 2 |
|
||||
| Insert heading 3 | Ctrl Alt 3 | Ctrl Alt 3 | ⌘ ⌥ 3 |
|
||||
| Insert heading 4 | Ctrl Alt 4 | Ctrl Alt 4 | ⌘ ⌥ 4 |
|
||||
| Insert heading 5 | Ctrl Alt 5 | Ctrl Alt 5 | ⌘ ⌥ 5 |
|
||||
| Insert heading 6 | Ctrl Alt 6 | Ctrl Alt 6 | ⌘ ⌥ 6 |
|
||||
| Undo | Ctrl Z | Ctrl Z | ⌘ Z |
|
||||
| Redo | Ctrl ⇧ Z / Ctrl Y | Ctrl ⇧ Z / Ctrl Y | ⌘ ⇧ Z / ⌘ Y |
|
||||
| Add image | Ctrl ⇧ I | Ctrl ⇧ I | ⌘ ⇧ I |
|
||||
| Toggle italic | Ctrl I | Ctrl I | ⌘ I |
|
||||
| Remove formatting in selection | Ctrl \ | Ctrl \ | ⌘ \ |
|
||||
| Insert internal link | Ctrl ⇧ K | Ctrl ⇧ K | ⌘ ⇧ K |
|
||||
| Insert link | Ctrl K | Ctrl K | ⌘ K |
|
||||
| Insert math block | Ctrl ⇧ M | Ctrl ⇧ M | ⌘ ⇧ M |
|
||||
| Toggle ordered list | Ctrl ⇧ 7 | Ctrl ⇧ 7 | ⌘ ⇧ 7 |
|
||||
| Toggle outline list | Ctrl ⇧ O | Ctrl ⇧ O | ⌘ ⇧ O |
|
||||
| Toggle outline list expand | Ctrl Space | Ctrl Space | ⌘ Space |
|
||||
| Open search | Ctrl F | Ctrl F | ⌘ F |
|
||||
| Toggle strike | Ctrl ⇧ S | Ctrl ⇧ S | ⌘ ⇧ S |
|
||||
| Toggle subscript | Ctrl , | Ctrl , | ⌘ , |
|
||||
| Toggle superscript | Ctrl . | Ctrl . | ⌘ . |
|
||||
| Toggle task list | Ctrl ⇧ T | Ctrl ⇧ T | ⌘ ⇧ T |
|
||||
| Text align center | Ctrl ⇧ E | Ctrl ⇧ E | ⌘ ⇧ E |
|
||||
| Text align justify | Ctrl ⇧ J | Ctrl ⇧ J | ⌘ ⇧ J |
|
||||
| Text align left | Ctrl ⇧ L | Ctrl ⇧ L | ⌘ ⇧ L |
|
||||
| Text align right | Ctrl ⇧ R | Ctrl ⇧ R | ⌘ ⇧ R |
|
||||
| Underline | Ctrl U | Ctrl U | ⌘ U |
|
||||
@@ -54,7 +54,6 @@ navigation:
|
||||
- path: deleting-your-account.md
|
||||
- path: app-lock.md
|
||||
- path: gift-cards.md
|
||||
- path: keyboard-shortcuts.md
|
||||
|
||||
- path: privacy-mode.md
|
||||
- path: web-clipper
|
||||
|
||||
49
docs/help/package-lock.json
generated
49
docs/help/package-lock.json
generated
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"name": "@notesnook/docs-help",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/docs-help",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@notesnook/common": "file:../../packages/common"
|
||||
}
|
||||
},
|
||||
"../../../packages/common": {
|
||||
"extraneous": true
|
||||
},
|
||||
"../../packages/common": {
|
||||
"name": "@notesnook/common",
|
||||
"version": "2.1.3",
|
||||
"dev": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@notesnook/core": "file:../core",
|
||||
"@readme/data-urls": "^3.0.0",
|
||||
"dayjs": "1.11.13",
|
||||
"pathe": "^1.1.2",
|
||||
"timeago.js": "4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@notesnook/core": "file:../core",
|
||||
"@types/react": "18.3.5",
|
||||
"react": "18.3.1",
|
||||
"vitest": "2.1.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"timeago.js": "4.0.2"
|
||||
}
|
||||
},
|
||||
"../common": {
|
||||
"extraneous": true
|
||||
},
|
||||
"node_modules/@notesnook/common": {
|
||||
"resolved": "../../packages/common",
|
||||
"link": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "@notesnook/docs-help",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"document-keyboard-shortcuts": "node scripts/document-keyboard-shortcuts.mjs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/streetwriters/notesnook.git"
|
||||
},
|
||||
"keywords": [
|
||||
"notesnook",
|
||||
"docs",
|
||||
"help"
|
||||
],
|
||||
"author": "",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://github.com/streetwriters/notesnook/issues"
|
||||
},
|
||||
"homepage": "https://github.com/streetwriters/notesnook#readme",
|
||||
"devDependencies": {
|
||||
"@notesnook/common": "file:../../packages/common"
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { writeFileSync } from "fs";
|
||||
import {
|
||||
getGroupedKeybindings,
|
||||
formatKey,
|
||||
macify,
|
||||
CATEGORIES
|
||||
} from "@notesnook/common";
|
||||
|
||||
console.log("Generating keyboard shortcuts documentation...");
|
||||
|
||||
const keyboardShortcutFilePath = "./contents/keyboard-shortcuts.md";
|
||||
|
||||
const frontmatter = `---
|
||||
title: Keyboard Shortcuts
|
||||
description: Keyboard shortcuts for Notesnook
|
||||
---
|
||||
`;
|
||||
|
||||
const content = `# Keyboard shortcuts
|
||||
|
||||
The following keyboard shortcuts will help you navigate Notesnook faster.`;
|
||||
|
||||
const markdownTable = getGroupedTableKeybindingsMarkdown();
|
||||
|
||||
writeFileSync(
|
||||
keyboardShortcutFilePath,
|
||||
frontmatter + "\n" + content + "\n\n" + markdownTable,
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
console.log("Keyboard shortcuts documentation updated successfully!");
|
||||
|
||||
/**
|
||||
* @returns markdown formatted table of keyboard shortcuts grouped by category.
|
||||
*/
|
||||
function getGroupedTableKeybindingsMarkdown() {
|
||||
const desktopKeybindings = getGroupedKeybindings(true, false);
|
||||
const webKeybindings = getGroupedKeybindings(false, false);
|
||||
|
||||
const header = `| Description | Web | Windows/Linux | Mac |
|
||||
| --- | --- | --- | --- |`;
|
||||
|
||||
return CATEGORIES.map((category) => {
|
||||
const webShortcuts =
|
||||
webKeybindings.find((g) => g.category === category)?.shortcuts || [];
|
||||
const desktopShortcuts =
|
||||
desktopKeybindings.find((g) => g.category === category)?.shortcuts || [];
|
||||
|
||||
const mergedShortcuts = {};
|
||||
|
||||
webShortcuts.forEach(({ description, keys }) => {
|
||||
if (!mergedShortcuts[description]) {
|
||||
mergedShortcuts[description] = {};
|
||||
}
|
||||
mergedShortcuts[description].web = keys;
|
||||
});
|
||||
desktopShortcuts.forEach(({ description, keys }) => {
|
||||
if (!mergedShortcuts[description]) {
|
||||
mergedShortcuts[description] = {};
|
||||
}
|
||||
mergedShortcuts[description].desktop = keys;
|
||||
});
|
||||
|
||||
const rows = Object.entries(mergedShortcuts)
|
||||
.map(([description, { web, desktop }]) => {
|
||||
const webKeys = web?.map((k) => formatKey(k)).join(" / ") || "-";
|
||||
const windowsLinuxKeys =
|
||||
desktop?.map((k) => formatKey(k)).join(" / ") || "-";
|
||||
const macKeys =
|
||||
desktop
|
||||
?.map(macify)
|
||||
.map((k) => formatKey(k, true))
|
||||
.join(" / ") || "-";
|
||||
|
||||
return `| ${description} | ${webKeys} | ${windowsLinuxKeys} | ${macKeys} |`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return `### ${category}\n\n${header}\n${rows}`;
|
||||
}).join("\n\n");
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
- Fix toolbar hidden behing keyboard on android 15 and 16
|
||||
- Fix sync performance issues
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,4 +0,0 @@
|
||||
- Fix PDF files get stuck on first page
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,4 +0,0 @@
|
||||
- Fix crash on device boot on android 15 devices
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,5 +0,0 @@
|
||||
- Fix crash on device boot on android 15 devices
|
||||
- Fix note not opening in editor randomly
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,3 +0,0 @@
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,4 +0,0 @@
|
||||
- Fix crash on android devices upgraded to android 16
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,4 +0,0 @@
|
||||
- Add scroll to top/bottom in editor
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
3
nx.json
3
nx.json
@@ -5,8 +5,7 @@
|
||||
"outputs": [
|
||||
"{projectRoot}/build",
|
||||
"{projectRoot}/dist",
|
||||
"{projectRoot}/languages",
|
||||
"{projectRoot}/src/extensions/code-block/languages"
|
||||
"{projectRoot}/languages"
|
||||
],
|
||||
"cache": true
|
||||
},
|
||||
|
||||
@@ -28,4 +28,3 @@ export * from "./migrate-toolbar.js";
|
||||
export * from "./export-notes.js";
|
||||
export * from "./dataurl.js";
|
||||
export * from "./tab-session-history.js";
|
||||
export * from "./keybindings.js";
|
||||
|
||||
@@ -1,485 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
interface Hotkeys {
|
||||
keys: (isDesktop: boolean) => string[];
|
||||
description: string;
|
||||
category: Category;
|
||||
type: "hotkeys";
|
||||
}
|
||||
|
||||
interface TipTapKey {
|
||||
keys: string | string[];
|
||||
description: string;
|
||||
category: Category;
|
||||
type: "tiptap";
|
||||
}
|
||||
|
||||
type Category = (typeof CATEGORIES)[number];
|
||||
|
||||
export const CATEGORIES = ["General", "Navigation", "Editor"] as const;
|
||||
|
||||
/**
|
||||
* consumed by hotkeys-js
|
||||
*/
|
||||
export const hotkeys = {
|
||||
nextTab: {
|
||||
keys: normalizeKeys({
|
||||
web: ["ctrl+alt+right", "ctrl+alt+shift+right"],
|
||||
desktop: ["ctrl+tab"]
|
||||
}),
|
||||
description: "Next tab",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
previousTab: {
|
||||
keys: normalizeKeys({
|
||||
web: ["ctrl+alt+left", "ctrl+alt+shift+left"],
|
||||
desktop: ["ctrl+shift+tab"]
|
||||
}),
|
||||
description: "Previous tab",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
newTab: {
|
||||
keys: normalizeKeys({
|
||||
desktop: ["ctrl+t"]
|
||||
}),
|
||||
description: "New tab",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
closeActiveTab: {
|
||||
keys: normalizeKeys({
|
||||
desktop: ["ctrl+w"]
|
||||
}),
|
||||
description: "Close active tab",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
closeAllTabs: {
|
||||
keys: normalizeKeys({
|
||||
desktop: ["ctrl+shift+w"]
|
||||
}),
|
||||
description: "Close all tabs",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
newNote: {
|
||||
keys: normalizeKeys({
|
||||
desktop: ["ctrl+n"]
|
||||
}),
|
||||
description: "New note",
|
||||
category: "General",
|
||||
type: "hotkeys"
|
||||
},
|
||||
searchInNotes: {
|
||||
keys: normalizeKeys(["ctrl+f"]),
|
||||
description: "Search in notes list view if editor is not focused",
|
||||
category: "General",
|
||||
type: "hotkeys"
|
||||
},
|
||||
openCommandPalette: {
|
||||
keys: normalizeKeys(["ctrl+shift+p"]),
|
||||
description: "Command palette",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
openQuickOpen: {
|
||||
keys: normalizeKeys(["ctrl+p"]),
|
||||
description: "Quick open",
|
||||
category: "Navigation",
|
||||
type: "hotkeys"
|
||||
},
|
||||
openSettings: {
|
||||
keys: normalizeKeys(["ctrl+,"]),
|
||||
description: "Settings",
|
||||
category: "General",
|
||||
type: "hotkeys"
|
||||
},
|
||||
openKeyboardShortcuts: {
|
||||
keys: normalizeKeys(["ctrl+/"]),
|
||||
description: "Keyboard shortcuts",
|
||||
category: "General",
|
||||
type: "hotkeys"
|
||||
}
|
||||
} satisfies Record<string, Hotkeys>;
|
||||
|
||||
/**
|
||||
* consumed by tiptap
|
||||
*/
|
||||
export const tiptapKeys = {
|
||||
addAttachment: {
|
||||
keys: "Mod-Shift-A",
|
||||
description: "Add attachment",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertBlockquote: {
|
||||
keys: "Mod-Shift-B",
|
||||
description: "Insert blockquote",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleBold: {
|
||||
keys: "Mod-b",
|
||||
description: "Toggle bold",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleBulletList: {
|
||||
keys: "Mod-Shift-8",
|
||||
description: "Toggle bullet list",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleCheckList: {
|
||||
keys: "Mod-Shift-9",
|
||||
description: "Toggle check list",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
splitListItem: {
|
||||
keys: "Enter",
|
||||
description: "Split list item",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
liftListItem: {
|
||||
keys: "Shift-Tab",
|
||||
description: "Lift list item",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
sinkListItem: {
|
||||
keys: "Mod-Shift-Down",
|
||||
description: "Sink list item",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleCode: {
|
||||
keys: "Mod-e",
|
||||
description: "Toggle code",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleCodeBlock: {
|
||||
keys: "Mod-Shift-C",
|
||||
description: "Toggle code block",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertDate: {
|
||||
keys: "Alt-d",
|
||||
description: "Insert date",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertTime: {
|
||||
keys: "Alt-t",
|
||||
description: "Insert time",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertDateTime: {
|
||||
keys: "Mod-Alt-d",
|
||||
description: "Insert date and time",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertDateTimeWithTimezone: {
|
||||
keys: "Mod-Alt-z",
|
||||
description: "Insert date and time with timezone",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
increaseFontSize: {
|
||||
keys: "Ctrl-[",
|
||||
description: "Increase font size",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
decreaseFontSize: {
|
||||
keys: "Ctrl-]",
|
||||
description: "Decrease font size",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertParagraph: {
|
||||
keys: "Mod-Shift-0",
|
||||
description: "Insert paragraph",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading1: {
|
||||
keys: "Mod-Alt-1",
|
||||
description: "Insert heading 1",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading2: {
|
||||
keys: "Mod-Alt-2",
|
||||
description: "Insert heading 2",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading3: {
|
||||
keys: "Mod-Alt-3",
|
||||
description: "Insert heading 3",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading4: {
|
||||
keys: "Mod-Alt-4",
|
||||
description: "Insert heading 4",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading5: {
|
||||
keys: "Mod-Alt-5",
|
||||
description: "Insert heading 5",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertHeading6: {
|
||||
keys: "Mod-Alt-6",
|
||||
description: "Insert heading 6",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
undo: {
|
||||
keys: "Mod-z",
|
||||
description: "Undo",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
redo: {
|
||||
keys: ["Mod-Shift-z", "Mod-y"],
|
||||
description: "Redo",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
addImage: {
|
||||
keys: "Mod-Shift-I",
|
||||
description: "Add image",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleItalic: {
|
||||
keys: "Mod-i",
|
||||
description: "Toggle italic",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
removeFormattingInSelection: {
|
||||
keys: "Mod-\\",
|
||||
description: "Remove formatting in selection",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertInternalLink: {
|
||||
keys: "Mod-Shift-K",
|
||||
description: "Insert internal link",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertLink: {
|
||||
keys: "Mod-k",
|
||||
description: "Insert link",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
insertMathBlock: {
|
||||
keys: "Mod-Shift-M",
|
||||
description: "Insert math block",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleOrderedList: {
|
||||
keys: "Mod-Shift-7",
|
||||
description: "Toggle ordered list",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleOutlineList: {
|
||||
keys: "Mod-Shift-O",
|
||||
description: "Toggle outline list",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleOutlineListExpand: {
|
||||
keys: "Mod-Space",
|
||||
description: "Toggle outline list expand",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
openSearch: {
|
||||
keys: "Mod-f",
|
||||
description: "Open search",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleStrike: {
|
||||
keys: "Mod-Shift-S",
|
||||
description: "Toggle strike",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleSubscript: {
|
||||
keys: "Mod-,",
|
||||
description: "Toggle subscript",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleSuperscript: {
|
||||
keys: "Mod-.",
|
||||
description: "Toggle superscript",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
toggleTaskList: {
|
||||
keys: "Mod-Shift-T",
|
||||
description: "Toggle task list",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
textAlignCenter: {
|
||||
keys: "Mod-Shift-E",
|
||||
description: "Text align center",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
textAlignJustify: {
|
||||
keys: "Mod-Shift-J",
|
||||
description: "Text align justify",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
textAlignLeft: {
|
||||
keys: "Mod-Shift-L",
|
||||
description: "Text align left",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
textAlignRight: {
|
||||
keys: "Mod-Shift-R",
|
||||
description: "Text align right",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
},
|
||||
underline: {
|
||||
keys: "Mod-u",
|
||||
description: "Underline",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
}
|
||||
} satisfies Record<string, TipTapKey>;
|
||||
|
||||
export const keybindings = {
|
||||
...hotkeys,
|
||||
...tiptapKeys
|
||||
};
|
||||
|
||||
export function getKeybinding(
|
||||
key: keyof typeof keybindings,
|
||||
isDesktop = false,
|
||||
isMac = false
|
||||
) {
|
||||
const keybinding = keybindings[key];
|
||||
if (keybinding.type === "hotkeys") {
|
||||
const hotkeys = keybinding.keys(isDesktop);
|
||||
return isMac ? hotkeys.map(macify) : hotkeys;
|
||||
}
|
||||
const tiptapKeys = Array.isArray(keybinding.keys)
|
||||
? keybinding.keys
|
||||
: [keybinding.keys];
|
||||
return isMac ? tiptapKeys.map(macify) : tiptapKeys;
|
||||
}
|
||||
|
||||
function normalizeKeys(
|
||||
keys: string[] | { web?: string[]; desktop?: string[] }
|
||||
): (isDesktop?: boolean) => string[] {
|
||||
return (isDesktop = false) => {
|
||||
let keyList: string[] = [];
|
||||
if (Array.isArray(keys)) {
|
||||
keyList = keys;
|
||||
} else {
|
||||
keyList = isDesktop ? keys.desktop ?? [] : keys.web ?? [];
|
||||
}
|
||||
return keyList;
|
||||
};
|
||||
}
|
||||
|
||||
export function macify(key: string) {
|
||||
return key
|
||||
.replace(/ctrl/gi, "Command")
|
||||
.replace(/alt/gi, "Option")
|
||||
.replace(/mod/gi, "Command");
|
||||
}
|
||||
|
||||
export function formatKey(key: string, isMac = false, separator = " ") {
|
||||
return key
|
||||
.replace(/\+|-/g, separator)
|
||||
.replace(/\bcommand\b/gi, isMac ? "⌘" : "Ctrl")
|
||||
.replace(/\bctrl\b/gi, isMac ? "⌘" : "Ctrl")
|
||||
.replace(/\bmod\b/gi, isMac ? "⌘" : "Ctrl")
|
||||
.replace(/\balt\b/gi, isMac ? "⌥" : "Alt")
|
||||
.replace(/\boption\b/gi, isMac ? "⌥" : "Alt")
|
||||
.replace(/\bshift\b/gi, "⇧")
|
||||
.replace(/\bright\b/gi, "→")
|
||||
.replace(/\bleft\b/gi, "←")
|
||||
.replace(/\benter\b/gi, "↵")
|
||||
.replace(/\b\w\b/gi, (e) => e.toUpperCase())
|
||||
.trim();
|
||||
}
|
||||
|
||||
export function getGroupedKeybindings(isDesktop: boolean, isMac: boolean) {
|
||||
const grouped: {
|
||||
shortcuts: { keys: string[]; description: string }[];
|
||||
category: Category;
|
||||
}[] = CATEGORIES.map((c) => ({
|
||||
category: c,
|
||||
shortcuts: []
|
||||
}));
|
||||
|
||||
const allKeybindings = { ...hotkeys, ...tiptapKeys };
|
||||
|
||||
for (const key in allKeybindings) {
|
||||
const binding = allKeybindings[key as keyof typeof allKeybindings];
|
||||
let keys =
|
||||
typeof binding.keys === "function"
|
||||
? binding.keys(isDesktop)
|
||||
: binding.keys;
|
||||
if (!keys || !keys.length) continue;
|
||||
|
||||
if (isMac) {
|
||||
keys = Array.isArray(keys) ? keys.map(macify) : macify(keys);
|
||||
}
|
||||
|
||||
const group = grouped.find((g) => g.category === binding.category);
|
||||
if (!group) throw new Error("Invalid group category: " + binding.category);
|
||||
|
||||
group.shortcuts.push({
|
||||
keys: Array.isArray(keys) ? keys : [keys],
|
||||
description: binding.description
|
||||
});
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
toBlobURL,
|
||||
usePermissionHandler
|
||||
} from "@notesnook/editor";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import FingerprintIcon from "mdi-react/FingerprintIcon";
|
||||
import {
|
||||
@@ -48,6 +47,7 @@ import StatusBar from "./statusbar";
|
||||
import Tags from "./tags";
|
||||
import TiptapEditorWrapper from "./tiptap";
|
||||
import Title from "./title";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
globalThis.toBlobURL = toBlobURL as typeof globalThis.toBlobURL;
|
||||
|
||||
@@ -380,15 +380,11 @@ const Tiptap = ({
|
||||
|
||||
const editor = editors[tab.id];
|
||||
|
||||
const firstChildNodeType = editor?.state.doc.firstChild?.type.name;
|
||||
const isSimpleNode =
|
||||
firstChildNodeType !== "image" &&
|
||||
firstChildNodeType !== "embed" &&
|
||||
firstChildNodeType !== "attachment" &&
|
||||
firstChildNodeType !== "mathBlock" &&
|
||||
firstChildNodeType !== "horizontalRule" &&
|
||||
firstChildNodeType !== "table";
|
||||
if (isSimpleNode) {
|
||||
const firstChild = editor?.state.doc.firstChild;
|
||||
const isParagraph = firstChild?.type.name === "paragraph";
|
||||
const isFirstChildEmpty =
|
||||
!firstChild?.textContent || firstChild?.textContent?.length === 0;
|
||||
if (isParagraph && isFirstChildEmpty) {
|
||||
editor?.commands.focus("end");
|
||||
return;
|
||||
}
|
||||
@@ -409,15 +405,11 @@ const Tiptap = ({
|
||||
const editor = editors[tab.id];
|
||||
const docSize = editor?.state.doc.content.size;
|
||||
if (!docSize) return;
|
||||
const lastChildNodeType = editor?.state.doc.lastChild?.type.name;
|
||||
const isSimpleNode =
|
||||
lastChildNodeType !== "image" &&
|
||||
lastChildNodeType !== "embed" &&
|
||||
lastChildNodeType !== "attachment" &&
|
||||
lastChildNodeType !== "mathBlock" &&
|
||||
lastChildNodeType !== "horizontalRule" &&
|
||||
lastChildNodeType !== "table";
|
||||
if (isSimpleNode) {
|
||||
const lastChild = editor?.state.doc.lastChild;
|
||||
const isParagraph = lastChild?.type.name === "paragraph";
|
||||
const isLastChildEmpty =
|
||||
!lastChild?.textContent || lastChild?.textContent?.length === 0;
|
||||
if (isParagraph && isLastChildEmpty) {
|
||||
editor?.commands.focus("end");
|
||||
return;
|
||||
}
|
||||
@@ -552,12 +544,10 @@ const Tiptap = ({
|
||||
<div
|
||||
onScroll={controller.scroll}
|
||||
ref={containerRef}
|
||||
id="editor-container-scroller"
|
||||
style={{
|
||||
overflowY: controller.loading ? "hidden" : "scroll",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: "block",
|
||||
position: "relative"
|
||||
}}
|
||||
>
|
||||
@@ -875,10 +865,9 @@ const Tiptap = ({
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
minHeight: 100
|
||||
minHeight: 300
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { ControlledMenu, MenuItem as MenuItemInner } from "@szhsin/react-menu";
|
||||
import ArrowBackIcon from "mdi-react/ArrowBackIcon";
|
||||
import ArrowTopIcon from "mdi-react/ArrowTopIcon";
|
||||
import ArrowDownIcon from "mdi-react/ArrowDownIcon";
|
||||
import ArrowForwardIcon from "mdi-react/ArrowForwardIcon";
|
||||
import ArrowULeftTopIcon from "mdi-react/ArrowULeftTopIcon";
|
||||
import ArrowURightTopIcon from "mdi-react/ArrowURightTopIcon";
|
||||
@@ -430,30 +428,6 @@ function Header({
|
||||
tab.session?.noteId
|
||||
);
|
||||
break;
|
||||
case "scroll-top":
|
||||
{
|
||||
const element = document.getElementById(
|
||||
"editor-container-scroller"
|
||||
);
|
||||
element?.scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "scroll-bottom":
|
||||
{
|
||||
const element = document.getElementById(
|
||||
"editor-container-scroller"
|
||||
);
|
||||
element?.scrollTo({
|
||||
top: element?.scrollHeight,
|
||||
left: 0,
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "properties":
|
||||
post(
|
||||
EditorEvents.properties,
|
||||
@@ -616,47 +590,6 @@ function Header({
|
||||
{strings.toc()}
|
||||
</span>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
value="scroll-top"
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<ArrowTopIcon
|
||||
size={22 * settings.fontScale}
|
||||
color="var(--nn_primary_icon)"
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
color: "var(--nn_primary_paragraph)"
|
||||
}}
|
||||
>
|
||||
{strings.scrollToTop()}
|
||||
</span>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
value="scroll-bottom"
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<ArrowDownIcon
|
||||
size={22 * settings.fontScale}
|
||||
color="var(--nn_primary_icon)"
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
color: "var(--nn_primary_paragraph)"
|
||||
}}
|
||||
>
|
||||
{strings.scrollToBottom()}
|
||||
</span>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
value="properties"
|
||||
style={{
|
||||
|
||||
@@ -22,7 +22,6 @@ import { Attribute } from "@tiptap/core";
|
||||
import { createNodeView } from "../react/index.js";
|
||||
import { AttachmentComponent } from "./component.js";
|
||||
import { Attachment } from "./types.js";
|
||||
import { tiptapKeys } from "@notesnook/common";
|
||||
|
||||
export type AttachmentType = "image" | "file" | "camera";
|
||||
export interface AttachmentOptions {
|
||||
@@ -162,7 +161,7 @@ export const AttachmentNode = Node.create<AttachmentOptions>({
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
[tiptapKeys.addAttachment.keys]: () =>
|
||||
"Mod-Shift-A": () =>
|
||||
this.editor.storage.openAttachmentPicker?.("file") || true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ 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 { tiptapKeys } from "@notesnook/common";
|
||||
import { getParentAttributes } from "../../utils/prosemirror.js";
|
||||
import { wrappingInputRule } from "@tiptap/core";
|
||||
import TiptapBlockquote, { inputRegex } from "@tiptap/extension-blockquote";
|
||||
@@ -48,13 +47,5 @@ export const Blockquote = TiptapBlockquote.extend({
|
||||
getAttributes: () => getParentAttributes(this.editor)
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
...this.parent?.(),
|
||||
[tiptapKeys.insertBlockquote.keys]: () =>
|
||||
this.editor.commands.toggleBlockquote()
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ 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 { keybindings } from "@notesnook/common";
|
||||
import { KeyboardShortcutCommand, mergeAttributes, Node } from "@tiptap/core";
|
||||
import { Node as ProseMirrorNode } from "@tiptap/pm/model";
|
||||
|
||||
@@ -81,8 +80,7 @@ export const CheckListItem = Node.create<CheckListItemOptions>({
|
||||
[key: string]: KeyboardShortcutCommand;
|
||||
} = {
|
||||
Enter: () => this.editor.commands.splitListItem(this.name),
|
||||
[keybindings.liftListItem.keys]: () =>
|
||||
this.editor.commands.liftListItem(this.name)
|
||||
"Shift-Tab": () => this.editor.commands.liftListItem(this.name)
|
||||
};
|
||||
|
||||
if (!this.options.nested) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import { mergeAttributes, Node, wrappingInputRule } from "@tiptap/core";
|
||||
import { inputRegex } from "@tiptap/extension-task-item";
|
||||
import { getParentAttributes } from "../../utils/prosemirror.js";
|
||||
import { ListItem } from "../list-item/index.js";
|
||||
import { tiptapKeys } from "@notesnook/common";
|
||||
|
||||
export interface CheckListOptions {
|
||||
itemTypeName: string;
|
||||
@@ -124,8 +123,7 @@ export const CheckList = Node.create<CheckListOptions>({
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
[tiptapKeys.toggleCheckList.keys]: () =>
|
||||
this.editor.commands.toggleCheckList()
|
||||
"Mod-Shift-9": () => this.editor.commands.toggleCheckList()
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,7 +36,6 @@ import stripIndent from "strip-indent";
|
||||
import { nanoid } from "nanoid";
|
||||
import Languages from "./languages.json";
|
||||
import { CaretPosition, CodeLine } from "./utils.js";
|
||||
import { tiptapKeys } from "@notesnook/common";
|
||||
|
||||
interface Indent {
|
||||
type: "tab" | "space";
|
||||
@@ -293,8 +292,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
[tiptapKeys.toggleCodeBlock.keys]: () =>
|
||||
this.editor.commands.toggleCodeBlock(),
|
||||
"Mod-Shift-C": () => this.editor.commands.toggleCodeBlock(),
|
||||
"Mod-a": ({ editor }) => {
|
||||
const { $anchor } = this.editor.state.selection;
|
||||
if ($anchor.parent.type.name !== this.name) {
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
InputRuleFinder,
|
||||
ExtendedRegExpMatchArray
|
||||
} from "@tiptap/core";
|
||||
import { formatDate, tiptapKeys } from "@notesnook/common";
|
||||
import { formatDate } from "@notesnook/common";
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
@@ -67,14 +67,10 @@ export const DateTime = Extension.create<DateTimeOptions>({
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
[tiptapKeys.insertTime.keys]: ({ editor }) =>
|
||||
editor.commands.insertTime(),
|
||||
[tiptapKeys.insertDate.keys]: ({ editor }) =>
|
||||
editor.commands.insertDate(),
|
||||
[tiptapKeys.insertDateTime.keys]: ({ editor }) =>
|
||||
editor.commands.insertDateTime(),
|
||||
[tiptapKeys.insertDateTimeWithTimezone.keys]: ({ editor }) =>
|
||||
editor.commands.insertDateTimeWithTimeZone()
|
||||
"Alt-t": ({ editor }) => editor.commands.insertTime(),
|
||||
"Alt-d": ({ editor }) => editor.commands.insertDate(),
|
||||
"Mod-Alt-d": ({ editor }) => editor.commands.insertDateTime(),
|
||||
"Mod-Alt-z": ({ editor }) => editor.commands.insertDateTimeWithTimeZone()
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 { tiptapKeys } from "@notesnook/common";
|
||||
import { useToolbarStore } from "../../toolbar/stores/toolbar-store.js";
|
||||
import { Editor, Extension } from "@tiptap/core";
|
||||
|
||||
@@ -87,7 +86,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
|
||||
},
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
[tiptapKeys.decreaseFontSize.keys]: ({ editor }) => {
|
||||
"ctrl-]": ({ editor }) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
@@ -95,7 +94,7 @@ export const FontSize = Extension.create<FontSizeOptions>({
|
||||
.run();
|
||||
return true;
|
||||
},
|
||||
[tiptapKeys.increaseFontSize.keys]: ({ editor }) => {
|
||||
"Ctrl-[": ({ editor }) => {
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 { tiptapKeys } from "@notesnook/common";
|
||||
import { textblockTypeInputRule } from "@tiptap/core";
|
||||
import { Heading as TiptapHeading } from "@tiptap/extension-heading";
|
||||
|
||||
@@ -50,8 +49,7 @@ export const Heading = TiptapHeading.extend({
|
||||
(items, level) => ({
|
||||
...items,
|
||||
...{
|
||||
[tiptapKeys[`insertHeading${level}`].keys]: () =>
|
||||
this.editor.commands.setHeading({ level })
|
||||
[`Mod-Alt-${level}`]: () => this.editor.commands.setHeading({ level })
|
||||
}
|
||||
}),
|
||||
{}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user