mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 11:08:47 +02:00
Compare commits
144 Commits
fix-file-c
...
fix-task-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2bbccf19e | ||
|
|
375dd18618 | ||
|
|
82f635305e | ||
|
|
00345176f7 | ||
|
|
9032e3b4bd | ||
|
|
432a9c4e84 | ||
|
|
aaaa9ebbc5 | ||
|
|
1ac4dca6b5 | ||
|
|
9dc549d0d3 | ||
|
|
775570fc13 | ||
|
|
997f0bc93e | ||
|
|
a2016e9406 | ||
|
|
87623aced1 | ||
|
|
24977277d0 | ||
|
|
2f890fd86b | ||
|
|
0220bb4040 | ||
|
|
09a8a0ba6d | ||
|
|
808670f6e1 | ||
|
|
62ab799a4a | ||
|
|
ecee87dac9 | ||
|
|
a5d52ded77 | ||
|
|
4e786a83f9 | ||
|
|
bf48ce788d | ||
|
|
f6637da274 | ||
|
|
6cd4a4a041 | ||
|
|
02ece7139e | ||
|
|
95203d723b | ||
|
|
b423cef2e6 | ||
|
|
e46b3ea85f | ||
|
|
0019c1f7af | ||
|
|
ffc4e2d263 | ||
|
|
c01ad2e49c | ||
|
|
9ff235e767 | ||
|
|
9b6f7ff225 | ||
|
|
99f97ac565 | ||
|
|
7e598098fe | ||
|
|
02afbf6c90 | ||
|
|
b464fafc18 | ||
|
|
e06320108b | ||
|
|
a377b13e2b | ||
|
|
4728212531 | ||
|
|
71fc2a3cac | ||
|
|
303282624e | ||
|
|
2ca02937df | ||
|
|
00b62df2e8 | ||
|
|
6d377ded9a | ||
|
|
087c404225 | ||
|
|
4932763468 | ||
|
|
abcc19d5da | ||
|
|
f1ce1e9b60 | ||
|
|
5a6f99a41b | ||
|
|
1862802052 | ||
|
|
1adddbdb4c | ||
|
|
15f4f2accb | ||
|
|
725f3c3522 | ||
|
|
efa73a1c32 | ||
|
|
00250c6669 | ||
|
|
d11afda1a8 | ||
|
|
1350784c33 | ||
|
|
1852a216a2 | ||
|
|
422c2492c4 | ||
|
|
c9c72741b3 | ||
|
|
99dbcaff7d | ||
|
|
8d83f5474d | ||
|
|
a912a1a22e | ||
|
|
ea7afbe93e | ||
|
|
7b2a8c3e20 | ||
|
|
911adfc151 | ||
|
|
23f710856e | ||
|
|
7f6274821c | ||
|
|
4700843517 | ||
|
|
8823054227 | ||
|
|
7c63a3e004 | ||
|
|
2a59154268 | ||
|
|
ed15d53484 | ||
|
|
fc8a4bb55d | ||
|
|
dd1c1bb11d | ||
|
|
3ffbad5727 | ||
|
|
207ae39d13 | ||
|
|
ae141ac9c5 | ||
|
|
40f058b14b | ||
|
|
865c9f3e32 | ||
|
|
26df9bfdd8 | ||
|
|
1e52e01fb8 | ||
|
|
5fece5faaa | ||
|
|
d7fdaf6c46 | ||
|
|
8e1faf9f60 | ||
|
|
9dce39b32d | ||
|
|
80a0b75887 | ||
|
|
c9704e1031 | ||
|
|
31e32cd154 | ||
|
|
61c296fc37 | ||
|
|
c8d38235b2 | ||
|
|
b717a64607 | ||
|
|
0f2b1d3e14 | ||
|
|
4abefe63db | ||
|
|
fc31b2a8d7 | ||
|
|
2708bac4fb | ||
|
|
a47967dd53 | ||
|
|
53ba5562d3 | ||
|
|
347df32943 | ||
|
|
ac8c63526b | ||
|
|
a48bd360ca | ||
|
|
f476969e9e | ||
|
|
c45539dea6 | ||
|
|
d8f5815b84 | ||
|
|
2eaf07118a | ||
|
|
b636b09a96 | ||
|
|
c16bbcaad5 | ||
|
|
49ffcbea03 | ||
|
|
f772cf0f14 | ||
|
|
3f1406a05b | ||
|
|
21760b2b74 | ||
|
|
d8011f0239 | ||
|
|
b9a8b054e2 | ||
|
|
2ab321869e | ||
|
|
fcb45a24d6 | ||
|
|
7cdb13def6 | ||
|
|
2ab58f9203 | ||
|
|
df74448e17 | ||
|
|
ada98fca93 | ||
|
|
1d3650659f | ||
|
|
9b43af475b | ||
|
|
d9c592c7fb | ||
|
|
f10ac9fbb5 | ||
|
|
b7334c09d4 | ||
|
|
0cd3bd5739 | ||
|
|
33d69480eb | ||
|
|
5cae4eb0d9 | ||
|
|
840c7fda5e | ||
|
|
4ce24ac8fd | ||
|
|
ae9e80e12e | ||
|
|
43356e5b6a | ||
|
|
7b13f35424 | ||
|
|
0517c6ce41 | ||
|
|
54d06328c1 | ||
|
|
c74677acd4 | ||
|
|
7689e1a7c5 | ||
|
|
5ffae2a08b | ||
|
|
5fa80abdc8 | ||
|
|
a30598fedf | ||
|
|
48ffecfb5f | ||
|
|
89fe712104 | ||
|
|
5dd298ee86 |
36
.github/workflows/desktop.publish.yml
vendored
36
.github/workflows/desktop.publish.yml
vendored
@@ -33,11 +33,19 @@ on:
|
||||
required: true
|
||||
default: true
|
||||
description: "Build for macOS?"
|
||||
release-track:
|
||||
type: choice
|
||||
required: true
|
||||
default: stable
|
||||
description: "Select the release track"
|
||||
options:
|
||||
- stable
|
||||
- beta
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -61,9 +69,14 @@ jobs:
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate desktop build
|
||||
- name: Generate desktop build (stable)
|
||||
if: ${{ inputs.release-track == 'stable' }}
|
||||
run: npx nx build:desktop @notesnook/web
|
||||
|
||||
- name: Generate desktop build (beta)
|
||||
if: ${{ inputs.release-track == 'beta' }}
|
||||
run: BETA=true npx nx build:desktop @notesnook/web
|
||||
|
||||
- name: Build desktop bundle
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run bundle
|
||||
@@ -99,7 +112,8 @@ jobs:
|
||||
- name: Generate flatpak sources
|
||||
if: inputs.publish-github && inputs.build-linux
|
||||
run: |
|
||||
sudo apt-get install -y flatpak flatpak-builder pipx
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --quiet flatpak flatpak-builder pipx
|
||||
git clone https://github.com/flatpak/flatpak-builder-tools.git /tmp/flatpak-builder-tools
|
||||
cd /tmp/flatpak-builder-tools/node
|
||||
pipx install .
|
||||
@@ -185,7 +199,7 @@ jobs:
|
||||
CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop -- --variant=mas
|
||||
yarn electron-builder --mac mas --universal -p never
|
||||
yarn electron-builder --config=electron-builder.config.js --mac mas --universal -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build zip and dmg
|
||||
@@ -199,9 +213,9 @@ jobs:
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --mac zip dmg --arm64 --x64 -p always
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p always
|
||||
else
|
||||
yarn electron-builder --mac zip dmg --arm64 --x64 -p never
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -263,7 +277,7 @@ jobs:
|
||||
- name: Build snap
|
||||
if: inputs.publish-snap
|
||||
run: |
|
||||
yarn electron-builder --linux snap:x64 -p never
|
||||
yarn electron-builder --config=electron-builder.config.js --linux snap:x64 -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build AppImage
|
||||
@@ -271,9 +285,9 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --linux AppImage:x64 AppImage:arm64 -p always
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -p always
|
||||
else
|
||||
yarn electron-builder --linux AppImage:x64 AppImage:arm64 -p never
|
||||
yarn electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
@@ -333,8 +347,8 @@ jobs:
|
||||
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
|
||||
run: |
|
||||
if ($${{ inputs.publish-github }} -eq $true) {
|
||||
yarn electron-builder --win --publish always
|
||||
yarn electron-builder --config=electron-builder.config.js --win --publish always
|
||||
} else {
|
||||
yarn electron-builder --win --publish never
|
||||
yarn electron-builder --config=electron-builder.config.js --win --publish never
|
||||
}
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
20
.github/workflows/desktop.tests.yml
vendored
20
.github/workflows/desktop.tests.yml
vendored
@@ -69,12 +69,11 @@ jobs:
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
yarn electron-builder --mac --dir --x64
|
||||
yarn electron-builder --config=electron-builder.config.js --mac --dir --x64
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Run tests x64
|
||||
run: |
|
||||
EXECUTABLE_PATH=output/mac/Notesnook.app/Contents/MacOS/Notesnook npm run test
|
||||
run: npm run test
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Upload test results
|
||||
@@ -114,12 +113,11 @@ jobs:
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
yarn electron-builder --mac --dir --arm64
|
||||
yarn electron-builder --config=electron-builder.config.js --mac --dir --arm64
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Run tests arm64
|
||||
run: |
|
||||
EXECUTABLE_PATH=output/mac-arm64/Notesnook.app/Contents/MacOS/Notesnook npm run test
|
||||
run: npm run test
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Upload test results
|
||||
@@ -165,12 +163,11 @@ jobs:
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
yarn electron-builder --linux --dir --arm64 --x64
|
||||
yarn electron-builder --config=electron-builder.config.js --linux --dir --arm64 --x64
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
EXECUTABLE_PATH=output/linux-unpacked/notesnook xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" -- npm run test
|
||||
run: xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" -- npm run test
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Upload test results
|
||||
@@ -216,12 +213,11 @@ jobs:
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
npx cross-env NOTESNOOK_STAGING=true yarn electron-builder --win --dir --arm64 --x64
|
||||
npx cross-env NOTESNOOK_STAGING=true yarn electron-builder --config=electron-builder.config.js --win --dir --arm64 --x64
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
npx cross-env EXECUTABLE_PATH=output/win-unpacked/Notesnook.exe npm run test
|
||||
run: npm run test
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Upload test results
|
||||
|
||||
30
.github/workflows/web.publish.yml
vendored
30
.github/workflows/web.publish.yml
vendored
@@ -1,6 +1,16 @@
|
||||
name: Publish @notesnook/web
|
||||
|
||||
on: workflow_dispatch
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release-track:
|
||||
type: choice
|
||||
required: true
|
||||
default: stable
|
||||
description: "Select the release track"
|
||||
options:
|
||||
- stable
|
||||
- beta
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -24,8 +34,20 @@ jobs:
|
||||
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate build
|
||||
- name: Generate build (stable)
|
||||
if: ${{ inputs.release-track == 'stable' }}
|
||||
run: npm run build:web
|
||||
|
||||
- name: Publish to Cloudflare Pages
|
||||
run: npx --yes wrangler pages deploy --project-name=notesnook-app ./apps/web/build/
|
||||
- name: Publish to Cloudflare Pages (stable)
|
||||
if: ${{ inputs.release-track == 'stable' }}
|
||||
working-directory: ./apps/web
|
||||
run: npx --yes wrangler pages deploy --project-name=notesnook-app ./build/
|
||||
|
||||
- name: Generate build (beta)
|
||||
if: ${{ inputs.release-track == 'beta' }}
|
||||
run: npm run build:beta:web
|
||||
|
||||
- name: Publish to Cloudflare Pages (beta)
|
||||
if: ${{ inputs.release-track == 'beta' }}
|
||||
working-directory: ./apps/web
|
||||
run: npx --yes wrangler pages deploy --branch=beta --project-name=notesnook-app-beta ./build/
|
||||
|
||||
2
.github/workflows/web.tests.yml
vendored
2
.github/workflows/web.tests.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
name: 🧪 Test (${{ matrix.shard }}/${{ strategy.job-total }})
|
||||
strategy:
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4]
|
||||
shard: [1, 2, 3, 4, 5]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
4
apps/desktop/.gitignore
vendored
4
apps/desktop/.gitignore
vendored
@@ -2,4 +2,6 @@ node_modules
|
||||
build
|
||||
output
|
||||
dist
|
||||
_catalog
|
||||
_catalog
|
||||
test-results
|
||||
test-artifacts
|
||||
|
||||
@@ -58,13 +58,13 @@ This will compile and run the app in production mode but it won't generate any p
|
||||
npm run release -- --rebuild
|
||||
|
||||
# For macOS
|
||||
npx electron-builder --mac dmg --arm64 --x64 -publish never
|
||||
npx electron-builder --config=electron-builder.config.js --mac dmg --arm64 --x64 -publish never
|
||||
|
||||
# For Linux (AppImage)
|
||||
npx electron-builder --linux AppImage:x64 AppImage:arm64 -publish never
|
||||
npx electron-builder --config=electron-builder.config.js --linux AppImage:x64 AppImage:arm64 -publish never
|
||||
|
||||
# For Windows
|
||||
npx electron-builder --win --publish never
|
||||
npx electron-builder --config=electron-builder.config.js --win --publish never
|
||||
```
|
||||
|
||||
Feel free to play around with the `electron-builder` command to get the packages you need. `npx electron-builder --help` is a great resource to learn different commands & platforms supported by `electron-builder`.
|
||||
|
||||
246
apps/desktop/__tests__/auto-updates.test.ts
Normal file
246
apps/desktop/__tests__/auto-updates.test.ts
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
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 } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { Page } from "playwright";
|
||||
import { gt, lt } from "semver";
|
||||
|
||||
test("update starts downloading if version is outdated", async (t) => {
|
||||
await harness(
|
||||
t,
|
||||
async ({ page }) => {
|
||||
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: /updating/i })
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
});
|
||||
|
||||
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.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: /available/i })
|
||||
.waitFor({ state: "attached" });
|
||||
},
|
||||
{ version: "3.0.0" }
|
||||
);
|
||||
});
|
||||
|
||||
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.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");
|
||||
|
||||
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" }
|
||||
);
|
||||
});
|
||||
|
||||
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"
|
||||
})
|
||||
);
|
||||
|
||||
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) {
|
||||
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();
|
||||
});
|
||||
}
|
||||
@@ -17,16 +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 test from "node:test";
|
||||
import { launchApp } from "./utils.mjs";
|
||||
import { test } from "vitest";
|
||||
import { harness } from "./utils.js";
|
||||
import assert from "assert";
|
||||
import slugify from "slugify";
|
||||
import path from "path";
|
||||
import { mkdir } from "fs/promises";
|
||||
|
||||
test("make sure app loads", async (t) => {
|
||||
const { app, page } = await launchApp();
|
||||
try {
|
||||
await harness(t, async ({ page }) => {
|
||||
await page.waitForSelector("#authForm");
|
||||
|
||||
assert.ok(
|
||||
@@ -38,16 +34,5 @@ test("make sure app loads", async (t) => {
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(".ProseMirror");
|
||||
} catch (e) {
|
||||
await mkdir("test-results", { recursive: true });
|
||||
await page.screenshot({
|
||||
path: path.join(
|
||||
"test-results",
|
||||
`${slugify(t.name)}-${process.platform}-${process.arch}-error.png`
|
||||
)
|
||||
});
|
||||
throw e;
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
172
apps/desktop/__tests__/utils.ts
Normal file
172
apps/desktop/__tests__/utils.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
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 { execSync } from "child_process";
|
||||
import { mkdir } from "fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "path";
|
||||
import { _electron as electron } from "playwright";
|
||||
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";
|
||||
|
||||
interface AppContext {
|
||||
app: import("playwright").ElectronApplication;
|
||||
page: import("playwright").Page;
|
||||
configPath: string;
|
||||
relaunch: () => Promise<void>;
|
||||
}
|
||||
|
||||
interface TestOptions {
|
||||
version: string;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
relaunch: async () => {
|
||||
const { app, page, configPath } = await launchApp(executablePath);
|
||||
ctx.app = app;
|
||||
ctx.page = page;
|
||||
ctx.configPath = configPath;
|
||||
}
|
||||
};
|
||||
return ctx;
|
||||
}
|
||||
|
||||
async function launchApp(executablePath: string) {
|
||||
const app = await electron.launch({
|
||||
executablePath,
|
||||
args: IS_DEBUG ? [] : ["--hidden"],
|
||||
env:
|
||||
process.platform === "linux"
|
||||
? {
|
||||
...(process.env as Record<string, string>),
|
||||
APPIMAGE: "true"
|
||||
}
|
||||
: (process.env as Record<string, string>)
|
||||
});
|
||||
|
||||
const page = await app.firstWindow();
|
||||
|
||||
const userDataDirectory = await app.evaluate((a) => {
|
||||
return a.app.getPath("userData");
|
||||
});
|
||||
const configPath = path.join(userDataDirectory, "config.json");
|
||||
return {
|
||||
app,
|
||||
page,
|
||||
configPath
|
||||
};
|
||||
}
|
||||
|
||||
async function buildApp({
|
||||
version,
|
||||
productName
|
||||
}: {
|
||||
version?: string;
|
||||
productName: string;
|
||||
}) {
|
||||
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 args = [
|
||||
`--config electron-builder.config.js`,
|
||||
`--c.extraMetadata.productName=${productName}`,
|
||||
"--publish=never"
|
||||
];
|
||||
if (version) args.push(`--c.extraMetadata.version=${version}`);
|
||||
|
||||
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 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) {
|
||||
let result = "";
|
||||
const characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const charactersLength = characters.length;
|
||||
let counter = 0;
|
||||
while (counter < length) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
counter += 1;
|
||||
}
|
||||
return result.toLowerCase();
|
||||
}
|
||||
Binary file not shown.
203
apps/desktop/electron-builder.config.js
Normal file
203
apps/desktop/electron-builder.config.js
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const pkg = require("./package.json");
|
||||
|
||||
const buildRoot = process.env.NN_BUILD_ROOT || ".";
|
||||
const buildFiles = [
|
||||
`${buildRoot}/build/`,
|
||||
`!${buildRoot}/build/screenshots\${/*}`,
|
||||
`!${buildRoot}/build/banner.jpg`,
|
||||
`!${buildRoot}/build/*.ico`,
|
||||
`!${buildRoot}/build/*.png`
|
||||
];
|
||||
|
||||
const productName = process.env.NN_PRODUCT_NAME || "Notesnook";
|
||||
const appId = process.env.NN_APP_ID || "org.streetwriters.notesnook";
|
||||
const outputDir = process.env.NN_OUTPUT_DIR || "output";
|
||||
const linuxExecutableName = process.env.NN_PRODUCT_NAME
|
||||
? process.env.NN_PRODUCT_NAME.toLowerCase().replace(/\s+/g, "-")
|
||||
: "notesnook";
|
||||
const year = new Date().getFullYear();
|
||||
const isBeta = pkg.version.includes("-beta");
|
||||
|
||||
module.exports = {
|
||||
appId: appId,
|
||||
productName: productName,
|
||||
copyright: `Copyright © ${year} Streetwriters (Private) Limited`,
|
||||
artifactName: "notesnook_${os}_${arch}.${ext}",
|
||||
generateUpdatesFilesForAllChannels: true,
|
||||
asar: false,
|
||||
files: [
|
||||
"!*.chunk.js.map",
|
||||
"!*.chunk.js.LICENSE.txt",
|
||||
...buildFiles,
|
||||
"!node_modules${/*}",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/build/Release/better_sqlite3.node",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/lib",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/package.json",
|
||||
"node_modules/file-uri-to-path",
|
||||
"node_modules/bindings",
|
||||
"node_modules/node-gyp-build",
|
||||
"node_modules/sqlite-better-trigram",
|
||||
"node_modules/sodium-native/prebuilds/${platform}-${arch}",
|
||||
{
|
||||
from: "node_modules/sqlite-better-trigram-linux-${arch}",
|
||||
to: "node_modules/sqlite-better-trigram-linux-${arch}"
|
||||
},
|
||||
{
|
||||
from: "node_modules/sqlite-better-trigram-darwin-${arch}",
|
||||
to: "node_modules/sqlite-better-trigram-darwin-${arch}"
|
||||
},
|
||||
{
|
||||
from: "node_modules/sqlite-better-trigram-windows-${arch}",
|
||||
to: "node_modules/sqlite-better-trigram-windows-${arch}"
|
||||
},
|
||||
"node_modules/sodium-native/index.js",
|
||||
"node_modules/sodium-native/package.json"
|
||||
],
|
||||
afterPack: "./scripts/removeLocales.js",
|
||||
mac: {
|
||||
bundleVersion: "240",
|
||||
minimumSystemVersion: "10.12.0",
|
||||
target: [
|
||||
{
|
||||
target: "dmg",
|
||||
arch: ["arm64", "x64"]
|
||||
},
|
||||
{
|
||||
target: "zip",
|
||||
arch: ["arm64", "x64"]
|
||||
}
|
||||
],
|
||||
category: "public.app-category.productivity",
|
||||
darkModeSupport: true,
|
||||
type: "distribution",
|
||||
hardenedRuntime: true,
|
||||
entitlements: "assets/entitlements.mac.plist",
|
||||
entitlementsInherit: "assets/entitlements.mac.plist",
|
||||
gatekeeperAssess: false,
|
||||
icon: "assets/icons/app.icns",
|
||||
notarize: true
|
||||
},
|
||||
dmg: {
|
||||
contents: [
|
||||
{
|
||||
x: 130,
|
||||
y: 220
|
||||
},
|
||||
{
|
||||
x: 410,
|
||||
y: 220,
|
||||
type: "link",
|
||||
path: "/Applications"
|
||||
}
|
||||
],
|
||||
icon: "assets/icons/app.icns",
|
||||
title: "Install Notesnook"
|
||||
},
|
||||
mas: {
|
||||
entitlements: "assets/entitlements.mas.plist",
|
||||
entitlementsInherit: "assets/entitlements.mas.inherit.plist",
|
||||
entitlementsLoginHelper: "assets/entitlements.mas.loginhelper.plist",
|
||||
hardenedRuntime: true
|
||||
},
|
||||
win: {
|
||||
target: [
|
||||
{
|
||||
target: "nsis",
|
||||
arch: ["x64", "arm64"]
|
||||
},
|
||||
{
|
||||
target: "portable",
|
||||
arch: ["x64", "arm64"]
|
||||
}
|
||||
],
|
||||
signtoolOptions: {
|
||||
signingHashAlgorithms: ["sha256"],
|
||||
sign: "./scripts/sign.js"
|
||||
},
|
||||
icon: "assets/icons/app.ico"
|
||||
},
|
||||
portable: {
|
||||
artifactName: "notesnook_${os}_${arch}_portable.${ext}"
|
||||
},
|
||||
nsis: {
|
||||
oneClick: true,
|
||||
createDesktopShortcut: "always",
|
||||
deleteAppDataOnUninstall: true
|
||||
},
|
||||
linux: {
|
||||
target: [
|
||||
{
|
||||
target: "AppImage",
|
||||
arch: ["x64", "arm64"]
|
||||
},
|
||||
{
|
||||
target: "snap",
|
||||
arch: ["x64", "arm64"]
|
||||
}
|
||||
],
|
||||
category: "Office",
|
||||
icon: "assets/icons/app.icns",
|
||||
description: "Your private note taking space",
|
||||
executableName: linuxExecutableName,
|
||||
desktop: {
|
||||
actions: [
|
||||
{
|
||||
id: "new-note",
|
||||
name: "New note",
|
||||
args: "new note"
|
||||
},
|
||||
{
|
||||
id: "new-notebook",
|
||||
name: "New notebook",
|
||||
args: "new notebook"
|
||||
},
|
||||
{
|
||||
id: "new-reminder",
|
||||
name: "New reminder",
|
||||
args: "new reminder"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
snap: {
|
||||
autoStart: false,
|
||||
confinement: "strict",
|
||||
allowNativeWayland: true
|
||||
},
|
||||
extraResources: ["app-update.yml", "./assets/**"],
|
||||
extraMetadata: {
|
||||
main: path.join(buildRoot, "build", "electron.js")
|
||||
},
|
||||
directories: {
|
||||
buildResources: "assets",
|
||||
output: outputDir
|
||||
},
|
||||
publish: [
|
||||
{
|
||||
provider: "github",
|
||||
repo: "notesnook",
|
||||
owner: "streetwriters",
|
||||
channel: isBeta ? "beta" : "latest"
|
||||
}
|
||||
]
|
||||
};
|
||||
15
apps/desktop/package-lock.json
generated
15
apps/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
@@ -15,7 +15,7 @@
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "11.5.0",
|
||||
"electron-trpc": "0.6.1",
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.3.4",
|
||||
"icojs": "^0.19.4",
|
||||
"sqlite-better-trigram": "0.0.2",
|
||||
@@ -38,7 +38,7 @@
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.19.8",
|
||||
"vitest": "2.1.8"
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -3190,9 +3190,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-trpc": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.6.1.tgz",
|
||||
"integrity": "sha512-Yj13UrjjjOW4+TD06YunAML2tgmtSYJMiFw6E6r1D4in/0EZ2MRwMoQc7AtMPAA6In23e+Kmq71e8h0ir+c3Jg==",
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-trpc/-/electron-trpc-0.7.1.tgz",
|
||||
"integrity": "sha512-aWjZ5pLeVhrX9A9d8O8YgR8N+q4IXXzc76CJT1PwtDijIw+y5I+c75IAAtZ4JayYLeR3ll95PNGl5RTBu2qePw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
@@ -6658,6 +6658,7 @@
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
|
||||
"integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "2.1.8",
|
||||
"@vitest/mocker": "2.1.8",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "11.5.0",
|
||||
"electron-trpc": "0.6.1",
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.3.4",
|
||||
"icojs": "^0.19.4",
|
||||
"sqlite-better-trigram": "0.0.2",
|
||||
@@ -46,14 +46,14 @@
|
||||
"electron": "^31.7.4",
|
||||
"electron-builder": "^25.1.8",
|
||||
"esbuild": "0.21.5",
|
||||
"vitest": "2.1.8",
|
||||
"node-abi": "^3.68.0",
|
||||
"node-gyp-build": "^4.8.2",
|
||||
"playwright": "^1.48.2",
|
||||
"prebuildify": "^6.0.1",
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.19.8"
|
||||
"undici": "^6.19.8",
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -63,203 +63,14 @@
|
||||
"staging": "node scripts/build.mjs --run",
|
||||
"release": "node scripts/build.mjs",
|
||||
"build": "node ../../scripts/build.mjs",
|
||||
"bundle": "esbuild electron=./src/main.ts ./src/preload.ts --external:electron --external:fsevents --external:better-sqlite3-multiple-ciphers --external:sodium-native --minify --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=false --define:RELEASE=true",
|
||||
"bundle": "esbuild electron=./src/main.ts ./src/preload.ts --external:electron --external:fsevents --external:better-sqlite3-multiple-ciphers --external:sodium-native --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=false --define:RELEASE=true",
|
||||
"bundle:mas": "esbuild electron=./src/main.ts ./src/preload.ts --minify --external:electron --external:fsevents --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=true --define:RELEASE=true",
|
||||
"postinstall": "patch-package",
|
||||
"test": "node --test --test-timeout 30000 --test-force-exit"
|
||||
"test": "vitest run"
|
||||
},
|
||||
"author": {
|
||||
"name": "Streetwriters (Private) Limited",
|
||||
"email": "support@streetwriters.co",
|
||||
"url": "https://streetwriters.co"
|
||||
},
|
||||
"build": {
|
||||
"appId": "org.streetwriters.notesnook",
|
||||
"productName": "Notesnook",
|
||||
"copyright": "Copyright © 2023 Streetwriters (Private) Limited",
|
||||
"artifactName": "notesnook_${os}_${arch}.${ext}",
|
||||
"generateUpdatesFilesForAllChannels": true,
|
||||
"asar": false,
|
||||
"files": [
|
||||
"!*.chunk.js.map",
|
||||
"!*.chunk.js.LICENSE.txt",
|
||||
"build/",
|
||||
"!build/screenshots${/*}",
|
||||
"!build/banner.jpg",
|
||||
"!build/*.ico",
|
||||
"!build/*.png",
|
||||
"!node_modules${/*}",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/build/Release/better_sqlite3.node",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/lib",
|
||||
"node_modules/better-sqlite3-multiple-ciphers/package.json",
|
||||
"node_modules/file-uri-to-path",
|
||||
"node_modules/bindings",
|
||||
"node_modules/node-gyp-build",
|
||||
"node_modules/sqlite-better-trigram",
|
||||
"node_modules/sodium-native/prebuilds/${platform}-${arch}",
|
||||
{
|
||||
"from": "node_modules/sqlite-better-trigram-linux-${arch}",
|
||||
"to": "node_modules/sqlite-better-trigram-linux-${arch}"
|
||||
},
|
||||
{
|
||||
"from": "node_modules/sqlite-better-trigram-darwin-${arch}",
|
||||
"to": "node_modules/sqlite-better-trigram-darwin-${arch}"
|
||||
},
|
||||
{
|
||||
"from": "node_modules/sqlite-better-trigram-windows-${arch}",
|
||||
"to": "node_modules/sqlite-better-trigram-windows-${arch}"
|
||||
},
|
||||
"node_modules/sodium-native/index.js",
|
||||
"node_modules/sodium-native/package.json"
|
||||
],
|
||||
"afterPack": "./scripts/removeLocales.js",
|
||||
"mac": {
|
||||
"bundleVersion": "240",
|
||||
"minimumSystemVersion": "10.12.0",
|
||||
"target": [
|
||||
{
|
||||
"target": "dmg",
|
||||
"arch": [
|
||||
"arm64",
|
||||
"x64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "zip",
|
||||
"arch": [
|
||||
"arm64",
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": "public.app-category.productivity",
|
||||
"darkModeSupport": true,
|
||||
"type": "distribution",
|
||||
"hardenedRuntime": true,
|
||||
"entitlements": "assets/entitlements.mac.plist",
|
||||
"entitlementsInherit": "assets/entitlements.mac.plist",
|
||||
"gatekeeperAssess": false,
|
||||
"icon": "assets/icons/app.icns",
|
||||
"notarize": true
|
||||
},
|
||||
"dmg": {
|
||||
"contents": [
|
||||
{
|
||||
"x": 130,
|
||||
"y": 220
|
||||
},
|
||||
{
|
||||
"x": 410,
|
||||
"y": 220,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
}
|
||||
],
|
||||
"icon": "assets/icons/app.icns",
|
||||
"title": "Install Notesnook"
|
||||
},
|
||||
"mas": {
|
||||
"entitlements": "assets/entitlements.mas.plist",
|
||||
"entitlementsInherit": "assets/entitlements.mas.inherit.plist",
|
||||
"entitlementsLoginHelper": "assets/entitlements.mas.loginhelper.plist",
|
||||
"hardenedRuntime": true
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "portable",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"signtoolOptions": {
|
||||
"signingHashAlgorithms": [
|
||||
"sha256"
|
||||
],
|
||||
"sign": "./scripts/sign.js"
|
||||
},
|
||||
"icon": "assets/icons/app.ico"
|
||||
},
|
||||
"portable": {
|
||||
"artifactName": "notesnook_${os}_${arch}_portable.${ext}"
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": true,
|
||||
"createDesktopShortcut": "always",
|
||||
"deleteAppDataOnUninstall": true
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "snap",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": "Office",
|
||||
"icon": "assets/icons/app.icns",
|
||||
"description": "Your private note taking space",
|
||||
"executableName": "notesnook",
|
||||
"desktop": {
|
||||
"actions": [
|
||||
{
|
||||
"id": "new-note",
|
||||
"name": "New note",
|
||||
"args": "new note"
|
||||
},
|
||||
{
|
||||
"id": "new-notebook",
|
||||
"name": "New notebook",
|
||||
"args": "new notebook"
|
||||
},
|
||||
{
|
||||
"id": "new-reminder",
|
||||
"name": "New reminder",
|
||||
"args": "new reminder"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"snap": {
|
||||
"autoStart": false,
|
||||
"confinement": "strict",
|
||||
"allowNativeWayland": true
|
||||
},
|
||||
"extraResources": [
|
||||
"app-update.yml",
|
||||
"./assets/**"
|
||||
],
|
||||
"extraMetadata": {
|
||||
"main": "./build/electron.js"
|
||||
},
|
||||
"directories": {
|
||||
"buildResources": "assets",
|
||||
"output": "./output/"
|
||||
},
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
"repo": "notesnook",
|
||||
"owner": "streetwriters"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import { patchBetterSQLite3 } from "./patch-better-sqlite3.mjs";
|
||||
const args = yargs(process.argv);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const root = args.root || path.join(__dirname, "..");
|
||||
const skipTscBuild = args.skipTscBuild || false;
|
||||
|
||||
const webAppPath = path.resolve(path.join(__dirname, "..", "..", "web"));
|
||||
|
||||
await fs.rm("./build/", { force: true, recursive: true });
|
||||
await fs.rm(path.join(root, "build"), { force: true, recursive: true });
|
||||
|
||||
if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
|
||||
await exec(
|
||||
@@ -44,21 +46,25 @@ if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
|
||||
// temporary until there's support for prebuilt binaries for linux ARM
|
||||
if (os.platform() === "linux") await patchBetterSQLite3();
|
||||
|
||||
await fs.cp(path.join(webAppPath, "build"), "build", {
|
||||
await fs.cp(path.join(webAppPath, "build"), path.join(root, "build"), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
|
||||
if (args.variant === "mas") {
|
||||
await exec(`yarn run bundle:mas`);
|
||||
await exec(`yarn run bundle:mas --outdir=${path.join(root, "build")}`);
|
||||
} else {
|
||||
await exec(`yarn run bundle`);
|
||||
await exec(`yarn run bundle --outdir=${path.join(root, "build")}`);
|
||||
}
|
||||
|
||||
await exec(`yarn run build`);
|
||||
if (!skipTscBuild) {
|
||||
await exec(`yarn run build`);
|
||||
}
|
||||
|
||||
if (args.run) {
|
||||
await exec(`yarn electron-builder --dir --${process.arch}`);
|
||||
await exec(
|
||||
`yarn electron-builder --dir --${process.arch} --config=electron-builder.config.js`
|
||||
);
|
||||
if (process.platform === "win32") {
|
||||
await exec(`.\\output\\win-unpacked\\Notesnook.exe`);
|
||||
} else if (process.platform === "darwin") {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { dirname } from "path";
|
||||
import { resolvePath } from "../utils/resolve-path";
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import { AssetManager } from "../utils/asset-manager";
|
||||
import { isFlatpak } from "../utils";
|
||||
import { isFlatpak, isSnap } from "../utils";
|
||||
import { setupDesktopIntegration } from "../utils/desktop-integration";
|
||||
import { rm } from "fs/promises";
|
||||
import { disableCustomDns, enableCustomDns } from "../utils/custom-dns";
|
||||
@@ -49,6 +49,7 @@ const NotificationOptions = z.object({
|
||||
|
||||
export const osIntegrationRouter = t.router({
|
||||
isFlatpak: t.procedure.query(() => isFlatpak()),
|
||||
isSnap: t.procedure.query(() => isSnap()),
|
||||
|
||||
zoomFactor: t.procedure.query(() => config.zoomFactor),
|
||||
setZoomFactor: t.procedure.input(z.number()).mutation(({ input: factor }) => {
|
||||
|
||||
@@ -23,6 +23,7 @@ import { CancellationToken, autoUpdater } from "electron-updater";
|
||||
import type { AppUpdaterEvents } from "electron-updater/out/AppUpdater";
|
||||
import { z } from "zod";
|
||||
import { config } from "../utils/config";
|
||||
import { app } from "electron";
|
||||
|
||||
type UpdateInfo = { version: string };
|
||||
type Progress = { percent: number };
|
||||
@@ -33,6 +34,7 @@ let downloadTimeout: NodeJS.Timeout | undefined = undefined;
|
||||
|
||||
export const updaterRouter = t.router({
|
||||
autoUpdates: t.procedure.query(() => config.automaticUpdates),
|
||||
releaseTrack: t.procedure.query(() => config.releaseTrack),
|
||||
install: t.procedure.query(() => autoUpdater.quitAndInstall()),
|
||||
download: t.procedure.query(async () => {
|
||||
if (cancellationToken) return;
|
||||
@@ -67,7 +69,13 @@ export const updaterRouter = t.router({
|
||||
.mutation(({ input: { enabled } }) => {
|
||||
config.automaticUpdates = enabled;
|
||||
}),
|
||||
|
||||
changeReleaseTrack: t.procedure
|
||||
.input(z.object({ track: z.string() }))
|
||||
.mutation(({ input: { track } }) => {
|
||||
config.releaseTrack = track;
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
}),
|
||||
onChecking: createSubscription("checking-for-update"),
|
||||
onDownloaded: createSubscription<"update-downloaded", UpdateInfo>(
|
||||
"update-downloaded"
|
||||
|
||||
@@ -85,6 +85,8 @@ async function createWindow() {
|
||||
const mainWindowState = new WindowState({});
|
||||
const mainWindow = new BrowserWindow({
|
||||
show: !cliOptions.hidden,
|
||||
paintWhenInitiallyHidden: cliOptions.hidden,
|
||||
skipTaskbar: cliOptions.hidden,
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
@@ -101,7 +103,10 @@ async function createWindow() {
|
||||
...(config.desktopSettings.nativeTitlebar
|
||||
? {}
|
||||
: {
|
||||
titleBarStyle: process.platform === "win32" || process.platform === "darwin" ? "hidden" : "default",
|
||||
titleBarStyle:
|
||||
process.platform === "win32" || process.platform === "darwin"
|
||||
? "hidden"
|
||||
: "default",
|
||||
frame: process.platform === "win32" || process.platform === "darwin",
|
||||
titleBarOverlay: {
|
||||
height: 37,
|
||||
@@ -142,6 +147,11 @@ async function createWindow() {
|
||||
await AssetManager.loadIcons();
|
||||
setupDesktopIntegration(config.desktopSettings);
|
||||
|
||||
mainWindow.webContents.session.setPermissionRequestHandler(
|
||||
(webContents, permission, callback) => {
|
||||
callback(permission === "geolocation" ? false : true);
|
||||
}
|
||||
);
|
||||
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
|
||||
"http://dictionaries.notesnook.com/"
|
||||
);
|
||||
|
||||
@@ -20,19 +20,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import { config } from "./config";
|
||||
|
||||
const CHANNEL = autoUpdater.currentVersion.raw.endsWith("-beta")
|
||||
? "beta"
|
||||
: "latest";
|
||||
async function configureAutoUpdater() {
|
||||
const releaseTrack =
|
||||
config.releaseTrack === "stable" ? "latest" : config.releaseTrack;
|
||||
autoUpdater.setFeedURL({
|
||||
provider: "generic",
|
||||
url: `https://notesnook.com/api/v1/releases/${process.platform}/${CHANNEL}`,
|
||||
url: `https://notesnook.com/api/v1/releases/${process.platform}/${releaseTrack}`,
|
||||
useMultipleRangeRequest: false,
|
||||
channel: CHANNEL
|
||||
channel: releaseTrack
|
||||
});
|
||||
|
||||
autoUpdater.autoDownload = config.automaticUpdates;
|
||||
autoUpdater.allowDowngrade = false;
|
||||
autoUpdater.allowDowngrade =
|
||||
// only allow downgrade if the current version is a prerelease
|
||||
// and the user has changed the release track to stable
|
||||
config.releaseTrack === "stable" &&
|
||||
autoUpdater.currentVersion.prerelease.length > 0;
|
||||
autoUpdater.allowPrerelease = false;
|
||||
autoUpdater.autoInstallOnAppQuit = true;
|
||||
autoUpdater.disableWebInstaller = true;
|
||||
|
||||
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { nativeTheme } from "electron";
|
||||
import { JSONStorage } from "./json-storage";
|
||||
import { z } from "zod";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
|
||||
export const DesktopIntegration = z.object({
|
||||
autoStart: z.boolean().optional(),
|
||||
@@ -46,6 +47,9 @@ export const config = {
|
||||
automaticUpdates: true,
|
||||
proxyRules: "",
|
||||
customDns: true,
|
||||
releaseTrack: autoUpdater.currentVersion.raw.includes("-beta")
|
||||
? "beta"
|
||||
: "stable",
|
||||
|
||||
backgroundColor: nativeTheme.themeSource === "dark" ? "#0f0f0f" : "#ffffff",
|
||||
windowControlsIconColor:
|
||||
|
||||
@@ -29,3 +29,7 @@ export function isDevelopment() {
|
||||
export function isFlatpak() {
|
||||
return existsSync("/.flatpak-info");
|
||||
}
|
||||
|
||||
export function isSnap() {
|
||||
return process.env.SNAP !== undefined;
|
||||
}
|
||||
|
||||
40
apps/desktop/vitest.config.ts
Normal file
40
apps/desktop/vitest.config.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
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 { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
testTimeout: process.env.CI ? 120 * 1000 : 120 * 1000,
|
||||
sequence: {
|
||||
concurrent: true,
|
||||
shuffle: true
|
||||
},
|
||||
dir: "./__tests__/",
|
||||
exclude: [
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/cypress/**",
|
||||
"**/.{idea,git,cache,output,temp}/**",
|
||||
"**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*",
|
||||
"**/test-results/**",
|
||||
"**/test-artifacts/**"
|
||||
]
|
||||
}
|
||||
});
|
||||
@@ -80,8 +80,9 @@ export const Dialog = ({ context = "global" }) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hide();
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const show = useCallback(
|
||||
@@ -104,14 +105,14 @@ export const Dialog = ({ context = "global" }) => {
|
||||
eUnSubscribeEvent(eOpenSimpleDialog, show);
|
||||
eUnSubscribeEvent(eCloseSimpleDialog, hide);
|
||||
};
|
||||
}, [show]);
|
||||
}, [hide, show]);
|
||||
|
||||
const hide = () => {
|
||||
const hide = React.useCallback(() => {
|
||||
setChecked(false);
|
||||
values.current.inputValue = undefined;
|
||||
setVisible(false);
|
||||
dialogInfo.onClose();
|
||||
};
|
||||
dialogInfo.onClose?.();
|
||||
}, [dialogInfo]);
|
||||
|
||||
const onNegativePress = async () => {
|
||||
if (dialogInfo.onClose) {
|
||||
|
||||
@@ -76,7 +76,8 @@ const NoteItem = ({
|
||||
}: NoteItemProps) => {
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.noteId === item.id
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.session?.noteId ===
|
||||
item.id
|
||||
);
|
||||
const { colors } = useThemeColors();
|
||||
const compactMode = useIsCompactModeEnabled(
|
||||
|
||||
@@ -28,7 +28,8 @@ export const Filler = ({ item, color }: { item: Item; color?: string }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const isEditingNote = useTabStore(
|
||||
(state) =>
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.noteId === item.id
|
||||
state.tabs.find((t) => t.id === state.currentTab)?.session?.noteId ===
|
||||
item.id
|
||||
);
|
||||
|
||||
const [selected] = useIsSelected(item);
|
||||
|
||||
@@ -509,7 +509,8 @@ const onChangeTab = async (event) => {
|
||||
});
|
||||
} else {
|
||||
if (
|
||||
useTabStore.getState().getTab(useTabStore.getState().currentTab).locked
|
||||
useTabStore.getState().getTab(useTabStore.getState().currentTab).session
|
||||
?.locked
|
||||
) {
|
||||
eSendEvent(eUnlockNote);
|
||||
}
|
||||
@@ -523,7 +524,7 @@ const onChangeTab = async (event) => {
|
||||
|
||||
// Lock all tabs with locked notes...
|
||||
for (const tab of useTabStore.getState().tabs) {
|
||||
const noteId = useTabStore.getState().getTab(tab.id)?.noteId;
|
||||
const noteId = useTabStore.getState().getTab(tab.id)?.session?.noteId;
|
||||
if (!noteId) continue;
|
||||
const note = await db.notes.note(noteId);
|
||||
const locked = note && (await db.vaults.itemExists(note));
|
||||
|
||||
@@ -248,14 +248,13 @@ const useLockedNoteHandler = () => {
|
||||
);
|
||||
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
|
||||
useTabStore.getState().updateTab(tabRef.current.id, {
|
||||
session: {
|
||||
locked: false
|
||||
}
|
||||
item: note,
|
||||
refresh: true
|
||||
});
|
||||
} else {
|
||||
if (tabRef.current && tabRef.current.session?.locked) {
|
||||
editorController.current?.commands.focusPassInput();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -310,12 +309,8 @@ const useLockedNoteHandler = () => {
|
||||
}
|
||||
}
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
useTabStore.getState().updateTab(tabRef.current.id, {
|
||||
session: {
|
||||
locked: false
|
||||
}
|
||||
item: note,
|
||||
refresh: true
|
||||
});
|
||||
} catch (e) {
|
||||
ToastManager.show({
|
||||
|
||||
@@ -90,8 +90,14 @@ class Commands {
|
||||
|
||||
const locked = useTabStore.getState().getTab(tabId)?.session?.locked;
|
||||
if (Platform.OS === "android") {
|
||||
//this.ref.current?.requestFocus();
|
||||
setTimeout(async () => {
|
||||
if (
|
||||
locked &&
|
||||
useTabStore.getState().biometryAvailable &&
|
||||
useTabStore.getState().biometryEnrolled
|
||||
)
|
||||
return;
|
||||
|
||||
if (!this.ref) return;
|
||||
textInput.current?.focus();
|
||||
await this.sendCommand("focus", tabId, locked);
|
||||
@@ -170,13 +176,13 @@ class Commands {
|
||||
await this.sendCommand("clearTags", tabId);
|
||||
};
|
||||
|
||||
insertAttachment = async (attachment: Attachment, tabId: number) => {
|
||||
insertAttachment = async (attachment: Attachment, tabId: string) => {
|
||||
await this.sendCommand("insertAttachment", attachment, tabId);
|
||||
};
|
||||
|
||||
setAttachmentProgress = async (
|
||||
attachmentProgress: Partial<Attachment>,
|
||||
tabId: number
|
||||
tabId: string
|
||||
) => {
|
||||
await this.sendCommand("setAttachmentProgress", attachmentProgress, tabId);
|
||||
};
|
||||
@@ -185,7 +191,7 @@ class Commands {
|
||||
image: Omit<ImageAttributes, "bloburl"> & {
|
||||
dataurl: string;
|
||||
},
|
||||
tabId: number
|
||||
tabId: string
|
||||
) => {
|
||||
await this.sendCommand("insertImage", image, tabId);
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ const santizeUri = (uri: string) => {
|
||||
|
||||
type PickerOptions = {
|
||||
noteId?: string;
|
||||
tabId?: number;
|
||||
tabId?: string;
|
||||
type: "image" | "camera" | "file";
|
||||
reupload: boolean;
|
||||
hash?: string;
|
||||
|
||||
@@ -127,15 +127,8 @@ class LocalTabState {
|
||||
tabSession?.readonly !== readonly ||
|
||||
!noteId
|
||||
) {
|
||||
console.log("tab is refreshing...");
|
||||
return true;
|
||||
}
|
||||
console.log(
|
||||
"Tab refreshing...",
|
||||
state.editedAt < this.noteEditedTime[noteId]
|
||||
);
|
||||
|
||||
console.log(state.editedAt, this.noteEditedTime[noteId]);
|
||||
|
||||
return !state.editedAt || state.editedAt < this.noteEditedTime[noteId];
|
||||
}
|
||||
@@ -501,6 +494,7 @@ export const useEditor = (
|
||||
blockId?: string;
|
||||
session?: TabSessionItem;
|
||||
newTab?: boolean;
|
||||
refresh?: boolean;
|
||||
}) => {
|
||||
loadNoteMutex.runExclusive(async () => {
|
||||
if (!event) return;
|
||||
@@ -521,7 +515,12 @@ export const useEditor = (
|
||||
}
|
||||
if (event.newNote && !currentLoadingNoteId.current) {
|
||||
let tabId;
|
||||
if (useTabStore.getState().tabs.length === 0) {
|
||||
|
||||
const currentTab = useTabStore
|
||||
.getState()
|
||||
.getTab(useTabStore.getState().currentTab as string);
|
||||
|
||||
if (useTabStore.getState().tabs.length === 0 || currentTab?.pinned) {
|
||||
tabId = useTabStore.getState().newTab();
|
||||
} else {
|
||||
tabId = useTabStore.getState().currentTab;
|
||||
@@ -546,14 +545,14 @@ export const useEditor = (
|
||||
|
||||
const item = event.item;
|
||||
|
||||
const currentTab = useTabStore
|
||||
.getState()
|
||||
.getTab(useTabStore.getState().currentTab as string);
|
||||
|
||||
// If note is already open in a tab, focus that tab.
|
||||
if (useTabStore.getState().hasTabForNote(item.id) && !event.newTab) {
|
||||
const tabId = useTabStore.getState().getTabForNote(item.id);
|
||||
|
||||
const currentTab = useTabStore
|
||||
.getState()
|
||||
.getTab(useTabStore.getState().currentTab as string);
|
||||
|
||||
if (
|
||||
currentTab?.session?.noteId !== item.id &&
|
||||
tabId !== useTabStore.getState().currentTab
|
||||
@@ -574,11 +573,10 @@ export const useEditor = (
|
||||
? event.tabId
|
||||
: useTabStore.getState().currentTab;
|
||||
|
||||
console.log(tabId === useTabStore.getState().currentTab);
|
||||
|
||||
// Check if tab needs to be refreshed.
|
||||
if (!event.newTab) {
|
||||
if (
|
||||
!event.refresh &&
|
||||
tabId &&
|
||||
event.item.id === useTabStore.getState().getNoteIdForTab(tabId) &&
|
||||
!localTabState.current?.needsRefresh(
|
||||
@@ -624,10 +622,16 @@ export const useEditor = (
|
||||
|
||||
const tab = useTabStore.getState().getTab(tabId!);
|
||||
|
||||
if (useTabStore.getState().tabs.length === 0 || event.newTab) {
|
||||
if (
|
||||
useTabStore.getState().tabs.length === 0 ||
|
||||
event.newTab ||
|
||||
(currentTab?.pinned &&
|
||||
event.item.id !== currentTab?.session?.noteId)
|
||||
) {
|
||||
useTabStore.getState().newTab({
|
||||
session: session
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// A new session is created if the note is changed.
|
||||
// If the note is already opened, the session is updated.
|
||||
@@ -1040,6 +1044,17 @@ export const useEditor = (
|
||||
}, [isDefaultEditor, restoreEditorState]);
|
||||
|
||||
const onLoad = useCallback(async () => {
|
||||
const isAppLoading = useSettingStore.getState().isAppLoading;
|
||||
if (isAppLoading) {
|
||||
const sub = useSettingStore.subscribe((state) => {
|
||||
if (!state.isAppLoading) {
|
||||
sub();
|
||||
onLoad();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
postMessage(NativeEvents.theme, theme);
|
||||
});
|
||||
@@ -1082,9 +1097,8 @@ export const useEditor = (
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
state.current.initialLoadCalled = true;
|
||||
}
|
||||
state.current.initialLoadCalled = true;
|
||||
overlay(false);
|
||||
}
|
||||
}, [
|
||||
|
||||
@@ -97,15 +97,16 @@ class TabSessionStorage {
|
||||
static storage: typeof TabSessionStorageKV = TabSessionStorageKV;
|
||||
|
||||
static get(id: string): TabSessionItem | null {
|
||||
if (!id) return null;
|
||||
return TabSessionStorage.storage.getMap(id);
|
||||
}
|
||||
|
||||
static set(id: string, session: TabSessionItem): void {
|
||||
if (!id) return;
|
||||
TabSessionStorage.storage.setMap(id, session);
|
||||
}
|
||||
|
||||
static update(id: string, session: Partial<TabSessionItem>) {
|
||||
if (!id) throw new Error("Session ID is required");
|
||||
const currentSession = TabSessionStorage.get(id);
|
||||
const newSession = {
|
||||
...currentSession,
|
||||
@@ -118,6 +119,7 @@ class TabSessionStorage {
|
||||
}
|
||||
|
||||
static remove(id: string) {
|
||||
if (!id) return;
|
||||
TabSessionStorageKV.removeItem(id);
|
||||
}
|
||||
}
|
||||
@@ -267,6 +269,7 @@ export const useTabStore = create<TabStore>(
|
||||
TabSessionStorage.set(sessionId, session as TabSessionItem);
|
||||
} else {
|
||||
session = {
|
||||
id: sessionId,
|
||||
...TabSessionStorage.get(oldSessionId),
|
||||
...options
|
||||
};
|
||||
@@ -317,13 +320,15 @@ export const useTabStore = create<TabStore>(
|
||||
const sessionLoaded = await get().loadSession(id);
|
||||
|
||||
if (!sessionLoaded) {
|
||||
tabSessionHistory.remove(currentTab, id);
|
||||
TabSessionStorage.remove(id);
|
||||
if (!tabSessionHistory.canGoBack(currentTab)) {
|
||||
const canGoBack = tabSessionHistory.canGoBack(currentTab);
|
||||
if (!canGoBack) {
|
||||
tabSessionHistory.forward(currentTab);
|
||||
syncTabs();
|
||||
} else {
|
||||
return get().goBack();
|
||||
get().goBack();
|
||||
tabSessionHistory.remove(currentTab, id);
|
||||
TabSessionStorage.remove(id);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
syncTabs();
|
||||
@@ -336,13 +341,15 @@ export const useTabStore = create<TabStore>(
|
||||
if (!tabSessionHistory.canGoForward(currentTab)) return;
|
||||
const id = tabSessionHistory.forward(currentTab) as string;
|
||||
if (!(await get().loadSession(id))) {
|
||||
tabSessionHistory.remove(currentTab, id);
|
||||
TabSessionStorage.remove(id);
|
||||
if (!tabSessionHistory.canGoForward(currentTab)) {
|
||||
const canGoForward = tabSessionHistory.canGoForward(currentTab);
|
||||
if (!canGoForward) {
|
||||
tabSessionHistory.back(currentTab);
|
||||
syncTabs();
|
||||
} else {
|
||||
return get().goForward();
|
||||
get().goForward();
|
||||
tabSessionHistory.remove(currentTab, id);
|
||||
TabSessionStorage.remove(id);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
syncTabs();
|
||||
@@ -358,8 +365,8 @@ export const useTabStore = create<TabStore>(
|
||||
|
||||
if (note) {
|
||||
const isLocked = await db.vaults.itemExists(note);
|
||||
session.noteLocked = isLocked;
|
||||
session.locked = isLocked;
|
||||
session.noteLocked = isLocked && !session?.noteLocked;
|
||||
|
||||
session.readonly = note.readonly;
|
||||
} else if (session.noteId) {
|
||||
@@ -399,7 +406,7 @@ export const useTabStore = create<TabStore>(
|
||||
set({
|
||||
tabs: [{ id: id }]
|
||||
});
|
||||
get().newTabSession(id, {});
|
||||
get().newTabSession(id);
|
||||
get().focusTab(id);
|
||||
} else {
|
||||
set({
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
StackActions,
|
||||
useNavigation
|
||||
} from "@react-navigation/native";
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { ActivityIndicator, TextInput, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import ToggleSwitch from "toggle-switch-react-native";
|
||||
@@ -41,7 +41,10 @@ import { RouteParams, SettingSection } from "./types";
|
||||
|
||||
const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
const { colors } = useThemeColors();
|
||||
const settings = useSettingStore((state) => state.settings);
|
||||
const [settings, itemProperty] = useSettingStore((state) => [
|
||||
state.settings,
|
||||
item.property ? state.settings[item.property] : null
|
||||
]);
|
||||
const navigation = useNavigation<NavigationProp<RouteParams>>();
|
||||
const current = item.useHook && item.useHook(item);
|
||||
const [isHidden, setIsHidden] = useState(
|
||||
@@ -103,6 +106,11 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setIsHidden(item.hidden && item.hidden(item.property || current));
|
||||
setIsDisabled(item.disabled && item.disabled(item.property || current));
|
||||
}, [current, item, itemProperty]);
|
||||
|
||||
return isHidden ? null : (
|
||||
<Pressable
|
||||
disabled={item.type === "component" || isDisabled}
|
||||
|
||||
@@ -451,7 +451,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
"local",
|
||||
"partial"
|
||||
);
|
||||
if (result.error) throw result.error as Error;
|
||||
if (result?.error) throw result.error as Error;
|
||||
} catch (e) {
|
||||
DatabaseLogger.error(e);
|
||||
const error = e;
|
||||
|
||||
@@ -169,7 +169,11 @@ async function run(
|
||||
progress = false,
|
||||
context?: string,
|
||||
backupType: "full" | "partial" = "partial"
|
||||
) {
|
||||
): Promise<{
|
||||
path?: string;
|
||||
error?: Error;
|
||||
report?: boolean;
|
||||
}> {
|
||||
if (backupRunning) {
|
||||
if (progress) {
|
||||
startProgress({
|
||||
@@ -179,7 +183,7 @@ async function run(
|
||||
canHideProgress: true
|
||||
});
|
||||
}
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
backupRunning = true;
|
||||
const androidBackupDirectory = (await checkBackupDirExists(
|
||||
@@ -343,7 +347,7 @@ async function run(
|
||||
endProgress();
|
||||
}
|
||||
return {
|
||||
error: e,
|
||||
error: e as Error,
|
||||
report: true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,17 @@ function resetSettings() {
|
||||
...defaultSettings,
|
||||
introCompleted: true,
|
||||
serverUrls: get().serverUrls,
|
||||
backupDirectoryAndroid: undefined
|
||||
backupDirectoryAndroid: get().backupDirectoryAndroid,
|
||||
darkTheme: get().darkTheme,
|
||||
lighTheme: get().lighTheme,
|
||||
useSystemTheme: get().useSystemTheme,
|
||||
colorScheme: get().colorScheme,
|
||||
defaultSnoozeTime: get().defaultSnoozeTime,
|
||||
defaultFontFamily: get().defaultFontFamily,
|
||||
defaultFontSize: get().defaultFontSize,
|
||||
privacyScreen: get().privacyScreen,
|
||||
corsProxy: get().corsProxy,
|
||||
showBackupCompleteSheet: get().showBackupCompleteSheet
|
||||
};
|
||||
|
||||
MMKV.setString("appSettings", JSON.stringify(settings));
|
||||
|
||||
@@ -116,7 +116,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3039
|
||||
versionCode 3042
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
- New and improved editor tabs with history
|
||||
- Fixed a crash on app launch faced by some users
|
||||
- Fixed homescreen note widget does not open correct note
|
||||
- Many small bug fixes and improvements
|
||||
- Small bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1063,7 +1063,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1137,7 +1137,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1168,7 +1168,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1242,7 +1242,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1401,7 +1401,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1413,7 +1413,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1444,7 +1444,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1457,7 +1457,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1487,7 +1487,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1561,7 +1561,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1592,7 +1592,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2126;
|
||||
CURRENT_PROJECT_VERSION = 2129;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1667,7 +1667,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.0.29;
|
||||
MARKETING_VERSION = 3.0.32;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"react-native-begin-background-task": "github:blockfirm/react-native-begin-background-task",
|
||||
"react-native-privacy-snapshot": "github:standardnotes/react-native-privacy-snapshot",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.0",
|
||||
"@ammarahmed/react-native-share-extension": "^2.8.0"
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"detox": "^20.27.6",
|
||||
|
||||
163
apps/mobile/package-lock.json
generated
163
apps/mobile/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.0.28",
|
||||
"version": "3.0.31",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.0.28",
|
||||
"version": "3.0.31",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -14,6 +14,7 @@
|
||||
"app/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.0",
|
||||
"@notesnook/common": "file:../../packages/common",
|
||||
"@notesnook/core": "file:../../packages/core",
|
||||
"@notesnook/crypto": "file:../../packages/crypto",
|
||||
@@ -7742,7 +7743,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/prop-types": {
|
||||
"version": "15.7.11",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/q": {
|
||||
@@ -7762,7 +7763,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/react": {
|
||||
"version": "18.2.39",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -7793,7 +7794,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/scheduler": {
|
||||
"version": "0.16.8",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/@types/semver": {
|
||||
@@ -12618,7 +12619,7 @@
|
||||
},
|
||||
"../../packages/editor-mobile/node_modules/immer": {
|
||||
"version": "9.0.21",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -23090,7 +23091,6 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"../../packages/editor/node_modules/jsesc": {
|
||||
@@ -23141,7 +23141,6 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
@@ -23653,7 +23652,6 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -23672,7 +23670,6 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
@@ -23811,7 +23808,6 @@
|
||||
},
|
||||
"../../packages/editor/node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -28319,7 +28315,6 @@
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.0",
|
||||
"@ammarahmed/react-native-share-extension": "^2.8.0",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.1",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"@callstack/repack": "^4.1.1",
|
||||
@@ -28457,9 +28452,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ammarahmed/react-native-share-extension": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-share-extension/-/react-native-share-extension-2.8.0.tgz",
|
||||
"integrity": "sha512-eDFVKiJJxjnIORveMUKVJGIhKfRNjqJWIoKS+JM88q8I8e3jHys9moyJAr9QM5oW/tZx4yyItl08yRXGnr7Grg==",
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-share-extension/-/react-native-share-extension-2.9.0.tgz",
|
||||
"integrity": "sha512-iEkpJQFZL5/WDPh7iRCLZREANgaaAHthDsPaAYT6sI4wieQcHZMBAnfRMwBEnC0BZ0WVxbQZdzJYez+dmwpr2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-native": "^0.63.1"
|
||||
}
|
||||
@@ -28594,7 +28590,6 @@
|
||||
},
|
||||
"node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
@@ -28714,7 +28709,6 @@
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
@@ -28974,7 +28968,6 @@
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz",
|
||||
"integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.25.9"
|
||||
},
|
||||
@@ -28989,7 +28982,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz",
|
||||
"integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
@@ -29138,7 +29130,6 @@
|
||||
"version": "7.21.0-placeholder-for-preset-env.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
|
||||
"integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
@@ -29151,7 +29142,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
|
||||
"integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
|
||||
"deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
|
||||
"@babel/helper-plugin-utils": "^7.18.6"
|
||||
@@ -29186,7 +29176,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-class-properties": {
|
||||
"version": "7.12.13",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.12.13"
|
||||
@@ -29199,7 +29188,6 @@
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
|
||||
"integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
},
|
||||
@@ -29237,7 +29225,6 @@
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
|
||||
"integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.8.3"
|
||||
},
|
||||
@@ -29262,7 +29249,6 @@
|
||||
"version": "7.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz",
|
||||
"integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -29277,7 +29263,6 @@
|
||||
"version": "7.25.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz",
|
||||
"integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -29292,7 +29277,6 @@
|
||||
"version": "7.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
|
||||
"integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.10.4"
|
||||
},
|
||||
@@ -29304,7 +29288,6 @@
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
|
||||
"integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.8.0"
|
||||
},
|
||||
@@ -29404,7 +29387,6 @@
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
|
||||
"integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.14.5"
|
||||
},
|
||||
@@ -29432,7 +29414,6 @@
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
|
||||
"integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
|
||||
"@babel/helper-plugin-utils": "^7.18.6"
|
||||
@@ -29461,7 +29442,6 @@
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.4.tgz",
|
||||
"integrity": "sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -29492,7 +29472,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoped-functions": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29521,7 +29500,6 @@
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz",
|
||||
"integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29537,7 +29515,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz",
|
||||
"integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -29602,7 +29579,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29618,7 +29594,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz",
|
||||
"integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -29633,7 +29608,6 @@
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz",
|
||||
"integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.25.9"
|
||||
},
|
||||
@@ -29646,7 +29620,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-exponentiation-operator": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5",
|
||||
@@ -29663,7 +29636,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz",
|
||||
"integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
|
||||
@@ -29691,7 +29663,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-for-of": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29722,7 +29693,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz",
|
||||
"integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3"
|
||||
@@ -29751,7 +29721,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz",
|
||||
"integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
|
||||
@@ -29765,7 +29734,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-member-expression-literals": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29781,7 +29749,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz",
|
||||
"integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29812,7 +29779,6 @@
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz",
|
||||
"integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
@@ -29830,7 +29796,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz",
|
||||
"integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -29860,7 +29825,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz",
|
||||
"integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -29890,7 +29854,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz",
|
||||
"integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-numeric-separator": "^7.10.4"
|
||||
@@ -29906,7 +29869,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz",
|
||||
"integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.22.5",
|
||||
@@ -29923,7 +29885,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-super": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -29940,7 +29901,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz",
|
||||
"integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
|
||||
@@ -30014,7 +29974,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-property-literals": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -30084,7 +30043,6 @@
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-regenerator": {
|
||||
"version": "7.22.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
@@ -30101,7 +30059,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz",
|
||||
"integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -30194,7 +30151,6 @@
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz",
|
||||
"integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -30225,7 +30181,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz",
|
||||
"integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
@@ -30240,7 +30195,6 @@
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz",
|
||||
"integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -30270,7 +30224,6 @@
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz",
|
||||
"integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-create-regexp-features-plugin": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
@@ -30286,7 +30239,6 @@
|
||||
"version": "7.25.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.4.tgz",
|
||||
"integrity": "sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.22.5",
|
||||
@@ -30380,7 +30332,6 @@
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz",
|
||||
"integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.0.0",
|
||||
"@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
|
||||
@@ -30396,7 +30347,6 @@
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -33700,8 +33650,7 @@
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||
},
|
||||
"node_modules/@types/graceful-fs": {
|
||||
"version": "4.1.6",
|
||||
@@ -33807,14 +33756,14 @@
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
|
||||
"integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -34170,7 +34119,6 @@
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
|
||||
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
@@ -34179,26 +34127,22 @@
|
||||
"node_modules/@webassemblyjs/floating-point-hex-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-api-error": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
|
||||
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
|
||||
"integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/floating-point-hex-parser": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
@@ -34208,14 +34152,12 @@
|
||||
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
|
||||
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
@@ -34227,7 +34169,6 @@
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
|
||||
"integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@xtuc/ieee754": "^1.2.0"
|
||||
}
|
||||
@@ -34236,7 +34177,6 @@
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
|
||||
"integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
@@ -34244,14 +34184,12 @@
|
||||
"node_modules/@webassemblyjs/utf8": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
|
||||
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
@@ -34267,7 +34205,6 @@
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
|
||||
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
@@ -34280,7 +34217,6 @@
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
|
||||
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
@@ -34292,7 +34228,6 @@
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
|
||||
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
@@ -34306,7 +34241,6 @@
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
|
||||
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@xtuc/long": "4.2.2"
|
||||
@@ -34364,14 +34298,12 @@
|
||||
"node_modules/@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
|
||||
},
|
||||
"node_modules/@xtuc/long": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
|
||||
},
|
||||
"node_modules/@yarnpkg/lockfile": {
|
||||
"version": "1.1.0",
|
||||
@@ -35370,7 +35302,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
|
||||
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
}
|
||||
@@ -35801,7 +35732,7 @@
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
@@ -36401,7 +36332,6 @@
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -36521,8 +36451,7 @@
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw=="
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
@@ -36867,7 +36796,6 @@
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
@@ -36880,7 +36808,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
@@ -37044,7 +36971,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
@@ -37056,7 +36982,6 @@
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
@@ -37065,7 +36990,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -37825,8 +37749,7 @@
|
||||
"node_modules/glob-to-regexp": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
|
||||
},
|
||||
"node_modules/global": {
|
||||
"version": "4.4.0",
|
||||
@@ -39915,8 +39838,7 @@
|
||||
"node_modules/json-parse-even-better-errors": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
|
||||
},
|
||||
"node_modules/json-schema-ref-resolver": {
|
||||
"version": "1.0.1",
|
||||
@@ -40392,7 +40314,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
|
||||
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.11.5"
|
||||
}
|
||||
@@ -42622,7 +42543,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
@@ -42644,6 +42564,30 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom/node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-freeze": {
|
||||
"version": "1.0.3",
|
||||
"license": "MIT",
|
||||
@@ -43563,7 +43507,6 @@
|
||||
},
|
||||
"node_modules/regenerator-transform": {
|
||||
"version": "0.15.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.4"
|
||||
@@ -43916,7 +43859,6 @@
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.1",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -44574,7 +44516,6 @@
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -44652,7 +44593,6 @@
|
||||
"version": "5.3.10",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
|
||||
"integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jest-worker": "^27.4.5",
|
||||
@@ -44686,7 +44626,6 @@
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
|
||||
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"merge-stream": "^2.0.0",
|
||||
@@ -44700,7 +44639,6 @@
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
@@ -45277,7 +45215,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -45301,7 +45238,6 @@
|
||||
"version": "5.94.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
|
||||
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
@@ -45417,7 +45353,6 @@
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.0.29",
|
||||
"version": "3.0.32",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -54,4 +54,4 @@
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.74.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ const ShareView = () => {
|
||||
</Paragraph>
|
||||
<ScrollView horizontal>
|
||||
{rawFiles.map((item) =>
|
||||
isImage(item.type) ? (
|
||||
isImage(item.type) || item.value?.endsWith(".png") ? (
|
||||
<TouchableOpacity
|
||||
onPress={() => onRemoveFile(item)}
|
||||
key={item.name}
|
||||
@@ -604,7 +604,8 @@ const ShareView = () => {
|
||||
paddingRight: 8
|
||||
}}
|
||||
>
|
||||
{item.name} ({formatBytes(item.size)})
|
||||
{item.name || item.value.split("/").pop()}
|
||||
{item.size ? `(${formatBytes(item.size)})` : ""}
|
||||
</Paragraph>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
FROM --platform=$BUILDPLATFORM oven/bun:1.1.36-alpine
|
||||
FROM oven/bun:1.2.2-alpine
|
||||
|
||||
RUN mkdir -p /home/bun/app && chown -R bun:bun /home/bun/app
|
||||
|
||||
@@ -11,4 +11,4 @@ COPY --chown=bun:bun output .
|
||||
|
||||
RUN bun install
|
||||
|
||||
CMD [ "bun", "run", "start" ]
|
||||
CMD [ "bun", "run", "start" ]
|
||||
|
||||
@@ -62,8 +62,42 @@ export default function handleRequest(
|
||||
|
||||
responseHeaders.set("Content-Type", "text/html; charset=utf-8");
|
||||
|
||||
const nonce =
|
||||
remixContext.staticHandlerContext?.loaderData?.root?.cspScriptNonce;
|
||||
if (nonce)
|
||||
responseHeaders.set(
|
||||
"Content-Security-Policy",
|
||||
getContentSecurityPolicy(nonce)
|
||||
);
|
||||
|
||||
return new Response(html, {
|
||||
status: responseStatusCode,
|
||||
headers: responseHeaders
|
||||
});
|
||||
}
|
||||
|
||||
function getContentSecurityPolicy(nonce?: string) {
|
||||
let script_src: string;
|
||||
if (typeof nonce === "string") {
|
||||
script_src = `'self' 'report-sample' 'nonce-${nonce}'`;
|
||||
} else if (process.env.NODE_ENV === "development") {
|
||||
// Allow the <LiveReload /> component to load without a nonce in the error pages
|
||||
script_src = "'self' 'report-sample'";
|
||||
} else {
|
||||
script_src = "'self' 'report-sample'";
|
||||
}
|
||||
|
||||
const connect_src =
|
||||
process.env.NODE_ENV === "development"
|
||||
? "'self' ws://localhost:*"
|
||||
: "'self'";
|
||||
|
||||
return (
|
||||
`script-src ${script_src} 'strict-dynamic'; ` +
|
||||
`connect-src ${connect_src}; ` +
|
||||
"form-action 'self'; " +
|
||||
"object-src 'none'; " +
|
||||
"block-all-mixed-content; " +
|
||||
"base-uri 'self'; manifest-src 'self'"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,22 @@ import {
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
ScrollRestoration
|
||||
ScrollRestoration,
|
||||
useLoaderData
|
||||
} from "@remix-run/react";
|
||||
import { BaseThemeProvider } from "./components/theme-provider";
|
||||
import { Buffer } from "buffer";
|
||||
import { ThemeDark, themeToCSS } from "@notesnook/theme";
|
||||
import { LoaderFunction } from "@remix-run/node";
|
||||
|
||||
globalThis.Buffer = Buffer;
|
||||
|
||||
type RootLoaderData = { cspScriptNonce: string };
|
||||
export const loader: LoaderFunction = async () => {
|
||||
const crypto = await import("node:crypto");
|
||||
return { cspScriptNonce: crypto.randomBytes(16).toString("hex") };
|
||||
};
|
||||
|
||||
export function Head() {
|
||||
return (
|
||||
<>
|
||||
@@ -40,13 +48,17 @@ export function Head() {
|
||||
<Links />
|
||||
<style
|
||||
id="theme-colors"
|
||||
dangerouslySetInnerHTML={{ __html: colorsToCSS() }}
|
||||
dangerouslySetInnerHTML={{ __html: themeToCSS(ThemeDark) }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const data = useLoaderData<RootLoaderData>();
|
||||
const cspScriptNonce =
|
||||
typeof document === "undefined" ? data.cspScriptNonce : "";
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseThemeProvider
|
||||
@@ -56,29 +68,8 @@ export default function App() {
|
||||
>
|
||||
<Outlet />
|
||||
</BaseThemeProvider>
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
<ScrollRestoration nonce={cspScriptNonce} />
|
||||
<Scripts nonce={cspScriptNonce} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function colorsToCSS() {
|
||||
// const colorScheme = JSON.parse(
|
||||
// window.localStorage.getItem("colorScheme") || '"light"'
|
||||
// );
|
||||
// const root = document.querySelector("html");
|
||||
// if (root) root.setAttribute("data-theme", colorScheme);
|
||||
|
||||
// const theme =
|
||||
// colorScheme === "dark"
|
||||
// ? JSON.parse(window.localStorage.getItem("theme:dark") || "false") ||
|
||||
// ThemeDark
|
||||
// : JSON.parse(window.localStorage.getItem("theme:light") || "false") ||
|
||||
// ThemeLight;
|
||||
// const stylesheet = document.getElementById("theme-colors");
|
||||
// if (theme) {
|
||||
// const css = ;
|
||||
// if (stylesheet) stylesheet.innerHTML = css;
|
||||
// } else stylesheet?.remove();
|
||||
return themeToCSS(ThemeDark);
|
||||
}
|
||||
|
||||
45
apps/monograph/package-lock.json
generated
45
apps/monograph/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.4",
|
||||
"dependencies": {
|
||||
"@emotion/cache": "11.11.0",
|
||||
"@emotion/react": "11.11.1",
|
||||
@@ -60,9 +60,6 @@
|
||||
"vite-plugin-static-copy": "^2.1.0",
|
||||
"vite-tsconfig-paths": "^5.0.1",
|
||||
"wrangler": "3.78.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"../../packages/core": {
|
||||
@@ -2945,6 +2942,22 @@
|
||||
"@styled-system/css": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/color-modes": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/color-modes/-/color-modes-0.16.2.tgz",
|
||||
"integrity": "sha512-jWEWx53lxNgWCT38i/kwLV2rsvJz8lVZgi5oImnVwYba9VejXD23q1ckbNFJHosQ8KKXY87ht0KPC6BQFIiHtQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@theme-ui/css": "^0.16.2",
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/components": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/components/-/components-0.16.2.tgz",
|
||||
@@ -2990,6 +3003,22 @@
|
||||
"@emotion/react": "^11.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/theme-provider": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/theme-provider/-/theme-provider-0.16.2.tgz",
|
||||
"integrity": "sha512-LRnVevODcGqO0JyLJ3wht+PV3ZoZcJ7XXLJAJWDoGeII4vZcPQKwVy4Lpz/juHsZppQxKcB3U+sQDGBnP25irQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/color-modes": "^0.16.2",
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@theme-ui/css": "^0.16.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/acorn": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
|
||||
@@ -3119,14 +3148,14 @@
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.10.tgz",
|
||||
"integrity": "sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -12212,7 +12241,7 @@
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.4",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
@@ -64,8 +64,5 @@
|
||||
"vite-plugin-static-copy": "^2.1.0",
|
||||
"vite-tsconfig-paths": "^5.0.1",
|
||||
"wrangler": "3.78.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
3481
apps/theme-builder/package-lock.json
generated
3481
apps/theme-builder/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/theme-builder",
|
||||
"description": "Your private note taking space",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
@@ -12,35 +12,25 @@
|
||||
"@mdi/js": "^7.2.96",
|
||||
"@mdi/react": "^1.6.1",
|
||||
"@notesnook/common": "file:../../packages/common",
|
||||
"@notesnook/intl": "file:../../packages/intl",
|
||||
"@notesnook/theme": "file:../../packages/theme",
|
||||
"@notesnook/web": "file:../web",
|
||||
"@streetwriters/kysely": "^0.27.4",
|
||||
"@theme-ui/components": "^0.14.7",
|
||||
"@theme-ui/core": "^0.14.7",
|
||||
"@trpc/client": "10.45.2",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"clipboard-polyfill": "^4.0.0",
|
||||
"dayjs": "1.11.13",
|
||||
"file-saver": "^2.0.5",
|
||||
"katex": "^0.16.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "18.2.0",
|
||||
"react-modal": "3.16.3",
|
||||
"@lingui/core": "5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.5",
|
||||
"@types/babel__core": "^7.20.1",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/react": "^18.2.39",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"buffer": "^6.0.3",
|
||||
"chalk": "^4.1.0",
|
||||
"happy-dom": "^8.9.0",
|
||||
"rollup": "^3.27.0",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"swc-plugin-react-remove-properties": "^0.1.4",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-env-compatible": "^1.1.1",
|
||||
"vite-plugin-svgr": "^3.2.0",
|
||||
"vitest": "^0.32.0"
|
||||
"vite": "5.4.11"
|
||||
},
|
||||
"overrides": {
|
||||
"@theme-ui/components@>0": "0.14.7",
|
||||
|
||||
13
apps/theme-builder/src/index.css
Normal file
13
apps/theme-builder/src/index.css
Normal file
@@ -0,0 +1,13 @@
|
||||
#root > .theme-scope-base {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
flex: 1;
|
||||
height: unset;
|
||||
}
|
||||
|
||||
#root > .theme-scope-base > :first-child:not(#menu-wrapper) {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -17,60 +17,44 @@ 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 { init } from "@notesnook/web/src/bootstrap";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import {
|
||||
ErrorBoundary,
|
||||
ErrorComponent
|
||||
} from "@notesnook/web/src/components/error-boundary";
|
||||
import { BaseThemeProvider } from "@notesnook/web/src/components/theme-provider";
|
||||
import "./index.css";
|
||||
import "@notesnook/web/src/polyfills";
|
||||
import "@notesnook/web/src/app.css";
|
||||
import { ThemeDark, ThemeLight, themeToCSS } from "@notesnook/theme";
|
||||
import Config from "@notesnook/web/src/utils/config";
|
||||
import { setI18nGlobal, Messages } from "@notesnook/intl";
|
||||
import { i18n } from "@lingui/core";
|
||||
import { App } from "./app";
|
||||
|
||||
renderApp();
|
||||
const colorScheme = JSON.parse(
|
||||
window.localStorage.getItem("colorScheme") || '"light"'
|
||||
);
|
||||
const root = document.querySelector("html");
|
||||
if (root) root.setAttribute("data-theme", colorScheme);
|
||||
|
||||
async function renderApp() {
|
||||
const rootElement = document.getElementById("root");
|
||||
if (!rootElement) return;
|
||||
const root = createRoot(rootElement);
|
||||
try {
|
||||
const { component, props } = await init();
|
||||
const theme =
|
||||
colorScheme === "dark"
|
||||
? Config.get("theme:dark", ThemeDark)
|
||||
: Config.get("theme:light", ThemeLight);
|
||||
const stylesheet = document.getElementById("theme-colors");
|
||||
if (theme) {
|
||||
const css = themeToCSS(theme);
|
||||
if (stylesheet) stylesheet.innerHTML = css;
|
||||
} else stylesheet?.remove();
|
||||
|
||||
const { useKeyStore } = await import(
|
||||
"@notesnook/web/src/interfaces/key-store"
|
||||
);
|
||||
await useKeyStore.getState().init();
|
||||
const locale = import.meta.env.DEV
|
||||
? import("@notesnook/intl/locales/$pseudo-LOCALE.json")
|
||||
: import("@notesnook/intl/locales/$en.json");
|
||||
locale.then(({ default: locale }) => {
|
||||
i18n.load({
|
||||
en: locale.messages as unknown as Messages
|
||||
});
|
||||
i18n.activate("en");
|
||||
|
||||
const { default: Component } = await component();
|
||||
const { default: AppLock } = await import(
|
||||
"@notesnook/web/src/views/app-lock"
|
||||
);
|
||||
|
||||
root.render(
|
||||
<ErrorBoundary>
|
||||
<BaseThemeProvider
|
||||
onRender={() => document.getElementById("splash")?.remove()}
|
||||
sx={{
|
||||
display: "flex",
|
||||
"#app": { flex: 1, height: "unset" },
|
||||
"& > :first-child:not(#menu-wrapper)": { flex: 1 },
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
<AppLock>
|
||||
<Component route={props?.route || "login:email"} />
|
||||
</AppLock>
|
||||
<App />
|
||||
</BaseThemeProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
} catch (e) {
|
||||
root.render(
|
||||
<>
|
||||
<ErrorComponent
|
||||
error={e}
|
||||
resetErrorBoundary={() => window.location.reload()}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
performance.mark("import:root");
|
||||
import("@notesnook/web/src/root.js").then(({ startApp }) => {
|
||||
performance.mark("start:app");
|
||||
startApp(<App />);
|
||||
});
|
||||
});
|
||||
setI18nGlobal(i18n);
|
||||
|
||||
@@ -26,7 +26,7 @@ type ErrorsListProps = {
|
||||
export function ErrorsList(props: ErrorsListProps) {
|
||||
return (
|
||||
<Accordion
|
||||
title={`${props.errors.length} errors occured`}
|
||||
title={`${props.errors.length} errors occurred`}
|
||||
sx={{ bg: "errorBg", borderRadius: "default", mt: 2 }}
|
||||
color="#E53935"
|
||||
>
|
||||
|
||||
3
apps/web/.gitignore
vendored
3
apps/web/.gitignore
vendored
@@ -30,4 +30,5 @@ dist
|
||||
public/workbox
|
||||
scripts/secrets
|
||||
test-results
|
||||
.swc
|
||||
.swc
|
||||
.wrangler
|
||||
|
||||
@@ -40,10 +40,12 @@ test("remove color", async ({ page }) => {
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
await app.navigation.waitForItem("red");
|
||||
const colorItem = await app.navigation.findItem("red");
|
||||
|
||||
await colorItem?.removeColor();
|
||||
|
||||
await expect(colorItem!.locator).toBeHidden();
|
||||
expect(await app.navigation.findItem("red")).toBeUndefined();
|
||||
expect(await note?.contextMenu.isColored("red")).toBe(false);
|
||||
});
|
||||
@@ -54,6 +56,7 @@ test("rename color", async ({ page }) => {
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
await app.navigation.waitForItem("red");
|
||||
const colorItem = await app.navigation.findItem("red");
|
||||
|
||||
await colorItem?.renameColor("priority-33");
|
||||
|
||||
@@ -20,31 +20,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { NotesViewModel } from "./models/notes-view.model";
|
||||
import { getTestId } from "./utils";
|
||||
|
||||
for (const item of [
|
||||
{ id: "notebooks", title: "Notebooks" },
|
||||
{ id: "tags", title: "Tags" }
|
||||
]) {
|
||||
test(`drag & hover over ${item.id} should navigate inside`, async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem(item.title);
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await expect(app.routeHeader).toHaveText(item.title);
|
||||
});
|
||||
test.skip(`drag & hover over ${item.id} should navigate inside`, () => {});
|
||||
}
|
||||
|
||||
test(`drag & drop note over Favorites should make the note favorite`, async ({
|
||||
@@ -85,24 +66,20 @@ test(`drag & drop note over a notebook should get assigned to the notebook`, asy
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "Test notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({ title: "Test notebook" });
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await notebook?.locator.hover();
|
||||
await notebook?.locator.hover();
|
||||
await page.mouse.up();
|
||||
|
||||
const { notes: notebookNotes } = (await notebook?.openNotebook()) || {};
|
||||
const notebookNotes = await notebook?.openNotebook();
|
||||
expect(await notebookNotes?.findNote({ title: "Test note" })).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -111,19 +88,15 @@ test(`drag & drop note over a tag should get assigned to the tag`, async ({
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const tags = await app.goToTags();
|
||||
const tag = await tags.createItem({ title: "Tag" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Tags");
|
||||
const tags = await app.goToTags();
|
||||
const tag = await tags.createItem({ title: "Tag" });
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await tag?.locator.hover();
|
||||
await tag?.locator.hover();
|
||||
await page.mouse.up();
|
||||
@@ -185,25 +158,20 @@ test(`drag & drop note over a nested notebook should get assigned to the noteboo
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook",
|
||||
subNotebooks: [{ title: "Nested notebook" }]
|
||||
});
|
||||
const nestedNotebook = await (
|
||||
await notebook?.openNotebook()
|
||||
)?.subNotebooks.createNotebook({ title: "Nested notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook"
|
||||
});
|
||||
const nestedNotebook = await notebook?.createSubnotebook({
|
||||
title: "Nested notebook"
|
||||
});
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await nestedNotebook?.locator.hover();
|
||||
await nestedNotebook?.locator.hover();
|
||||
await page.mouse.up();
|
||||
@@ -212,46 +180,3 @@ test(`drag & drop note over a nested notebook should get assigned to the noteboo
|
||||
const notebookNotes = new NotesViewModel(page, "notebook", "notes");
|
||||
expect(await notebookNotes?.findNote({ title: "Test note" })).toBeDefined();
|
||||
});
|
||||
|
||||
test(`drag & hover over a nested notebook should navigate inside`, async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook({
|
||||
title: "Test notebook",
|
||||
subNotebooks: [{ title: "Nested notebook" }]
|
||||
});
|
||||
const nestedNotebook = await (
|
||||
await notebook?.openNotebook()
|
||||
)?.subNotebooks.createNotebook({ title: "Nested notebook" });
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: `Test note`
|
||||
});
|
||||
const navigationItem = await app.navigation.findItem("Notebooks");
|
||||
await navigationItem?.click();
|
||||
await navigationItem?.click();
|
||||
await app.goToNotes();
|
||||
|
||||
await note?.locator.hover();
|
||||
await page.mouse.down();
|
||||
await navigationItem?.locator.hover();
|
||||
await navigationItem?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await notebook?.locator.hover();
|
||||
await notebook?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await nestedNotebook?.locator.hover();
|
||||
await nestedNotebook?.locator.hover();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
expect(
|
||||
await page
|
||||
.locator(getTestId("notebook-header"))
|
||||
.locator(getTestId("notebook-title"))
|
||||
.textContent()
|
||||
).toBe("Nested notebook");
|
||||
});
|
||||
|
||||
@@ -258,6 +258,21 @@ test("creating a new note and toggling read-only mode should not empty editor co
|
||||
expect(await notes.editor.getContent("text")).toBe(NOTE.content);
|
||||
});
|
||||
|
||||
test("toggling read-only should hide undo & redo buttons", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
|
||||
await notes.editor.undoButton.waitFor({ state: "visible" });
|
||||
await notes.editor.redoButton.waitFor({ state: "visible" });
|
||||
await note?.properties.readonly();
|
||||
|
||||
expect(await note?.properties.isReadonly()).toBeTruthy();
|
||||
expect(notes.editor.undoButton).not.toBeVisible();
|
||||
expect(notes.editor.redoButton).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("#1468 count words separated by newlines", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
@@ -347,7 +362,7 @@ test("when autosave is disabled, creating a new note should save the note", asyn
|
||||
await notes.newNote();
|
||||
|
||||
await note?.openNote();
|
||||
await expect(notes.editor.savedIcon).toBeVisible();
|
||||
// await expect(notes.editor.savedIcon).toBeVisible();
|
||||
expect(await notes.editor.getContent("text")).toBe(content.trim());
|
||||
});
|
||||
|
||||
@@ -385,7 +400,7 @@ test("control + alt + right arrow should go to next note", async ({ page }) => {
|
||||
});
|
||||
|
||||
await note1?.openNote();
|
||||
await note2?.openNote();
|
||||
await note2?.openNote(true);
|
||||
await page.keyboard.press("Control+Alt+ArrowRight");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 1");
|
||||
@@ -413,7 +428,7 @@ test("control + alt + left arrow should go to previous note", async ({
|
||||
});
|
||||
|
||||
await note1?.openNote();
|
||||
await note2?.openNote();
|
||||
await note2?.openNote(true);
|
||||
await page.keyboard.press("Control+Alt+ArrowLeft");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 1");
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 70 KiB |
@@ -1 +1 @@
|
||||
This is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1An edit I made
|
||||
An edit I madeThis is Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1Test 1
|
||||
@@ -30,6 +30,7 @@ import { SearchViewModel } from "./search-view-model";
|
||||
import { SettingsViewModel } from "./settings-view.model";
|
||||
import { ToastsModel } from "./toasts.model";
|
||||
import { TrashViewModel } from "./trash-view.model";
|
||||
import { ContextMenuModel } from "./context-menu.model";
|
||||
|
||||
export class AppModel {
|
||||
readonly page: Page;
|
||||
@@ -38,6 +39,7 @@ export class AppModel {
|
||||
readonly auth: AuthModel;
|
||||
readonly checkout: CheckoutModel;
|
||||
readonly routeHeader: Locator;
|
||||
private readonly profileDropdown: ContextMenuModel;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
@@ -46,56 +48,72 @@ export class AppModel {
|
||||
this.auth = new AuthModel(page);
|
||||
this.checkout = new CheckoutModel(page);
|
||||
this.routeHeader = this.page.locator(getTestId("routeHeader"));
|
||||
this.profileDropdown = new ContextMenuModel(this.page);
|
||||
}
|
||||
|
||||
async goto(isLoggedIn = false) {
|
||||
await this.page.goto("/");
|
||||
await this.routeHeader.waitFor({ state: "visible" });
|
||||
if (!isLoggedIn) await this.navigation.waitForItem("Login");
|
||||
}
|
||||
|
||||
goBack() {
|
||||
const goBackButton = this.page.locator(getTestId("route-go-back"));
|
||||
return goBackButton.click();
|
||||
if (!isLoggedIn)
|
||||
await this.page
|
||||
.locator(getTestId("logged-in"))
|
||||
.waitFor({ state: "hidden" });
|
||||
}
|
||||
|
||||
async goToNotes() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Notes");
|
||||
return new NotesViewModel(this.page, "home", "home");
|
||||
}
|
||||
|
||||
async goToNotebooks() {
|
||||
await this.navigateTo("Notebooks");
|
||||
return new NotebooksViewModel(this.page);
|
||||
await this.page.locator(getTestId("tab-notebooks")).click();
|
||||
const model = new NotebooksViewModel(this.page);
|
||||
await model.waitForList();
|
||||
return model;
|
||||
}
|
||||
|
||||
async goToFavorites() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Favorites");
|
||||
return new NotesViewModel(this.page, "notes", "favorites");
|
||||
}
|
||||
|
||||
async goToReminders() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Reminders");
|
||||
return new RemindersViewModel(this.page);
|
||||
}
|
||||
|
||||
async goToTags() {
|
||||
await this.navigateTo("Tags");
|
||||
return new ItemsViewModel(this.page);
|
||||
await this.page.locator(getTestId("tab-tags")).click();
|
||||
const model = new ItemsViewModel(this.page);
|
||||
await model.waitForList();
|
||||
return model;
|
||||
}
|
||||
|
||||
async goToHome() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
}
|
||||
|
||||
async goToColor(color: string) {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo(color);
|
||||
return new NotesViewModel(this.page, "notes", "notes");
|
||||
}
|
||||
|
||||
async goToTrash() {
|
||||
await this.page.locator(getTestId("tab-home")).click();
|
||||
await this.navigateTo("Trash");
|
||||
return new TrashViewModel(this.page);
|
||||
}
|
||||
|
||||
async goToSettings() {
|
||||
await this.navigateTo("Settings");
|
||||
await this.profileDropdown.open(
|
||||
this.page.locator(getTestId("profile-dropdown")),
|
||||
"left"
|
||||
);
|
||||
await this.profileDropdown.clickOnItem("settings");
|
||||
return new SettingsViewModel(this.page);
|
||||
}
|
||||
|
||||
@@ -111,7 +129,7 @@ export class AppModel {
|
||||
async getRouteHeader() {
|
||||
if (!(await this.routeHeader.isVisible())) return;
|
||||
|
||||
return await this.routeHeader.innerText();
|
||||
return await this.routeHeader.getAttribute("data-header");
|
||||
}
|
||||
|
||||
async isSynced() {
|
||||
|
||||
@@ -51,7 +51,11 @@ export class BaseViewModel {
|
||||
.locator(getTestId("group-header"));
|
||||
|
||||
for await (const item of iterateList(locator)) {
|
||||
if ((await item.locator(getTestId("title")).textContent()) === groupName)
|
||||
if (
|
||||
(
|
||||
await item.locator(getTestId("title")).textContent()
|
||||
)?.toLowerCase() === groupName.toLowerCase()
|
||||
)
|
||||
return item;
|
||||
}
|
||||
return undefined;
|
||||
@@ -95,7 +99,9 @@ export class BaseViewModel {
|
||||
// }
|
||||
|
||||
async press(key: string) {
|
||||
const itemList = this.list.locator(getTestId(`virtuoso-item-list`, "data-testid"));
|
||||
const itemList = this.list.locator(
|
||||
getTestId(`virtuoso-item-list`, "data-testid")
|
||||
);
|
||||
await itemList.press(key);
|
||||
await this.page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ export class EditorModel {
|
||||
private readonly newTabButton: Locator;
|
||||
readonly savedIcon: Locator;
|
||||
readonly notSavedIcon: Locator;
|
||||
readonly undoButton: Locator;
|
||||
readonly redoButton: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
@@ -65,6 +67,8 @@ export class EditorModel {
|
||||
this.goBackButton = page.locator(getTestId("go-back"));
|
||||
this.goForwardButton = page.locator(getTestId("go-forward"));
|
||||
this.newTabButton = page.locator(getTestId("New tab"));
|
||||
this.undoButton = page.locator(getTestId("Undo"));
|
||||
this.redoButton = page.locator(getTestId("Redo"));
|
||||
}
|
||||
|
||||
async waitForLoading(title?: string, content?: string) {
|
||||
@@ -89,7 +93,6 @@ export class EditorModel {
|
||||
}
|
||||
|
||||
async waitForUnloading() {
|
||||
await this.page.waitForURL(/#\/notes\/?.+\/create/gm);
|
||||
await this.searchButton.isDisabled();
|
||||
await this.page
|
||||
.locator(".active")
|
||||
@@ -101,7 +104,6 @@ export class EditorModel {
|
||||
}
|
||||
|
||||
async waitForSaving() {
|
||||
await this.page.waitForURL(/#\/notes\/?.+\/edit/gm);
|
||||
await this.page.locator(".active").locator(getTestId("tags")).waitFor();
|
||||
await this.searchButton.waitFor();
|
||||
await this.wordCountText.waitFor();
|
||||
@@ -124,7 +126,8 @@ export class EditorModel {
|
||||
async typeTitle(text: string, delay = 0) {
|
||||
await this.editAndWait(async () => {
|
||||
await this.title.focus();
|
||||
await this.title.press("End");
|
||||
await this.title.selectText();
|
||||
await this.title.press("ArrowRight");
|
||||
await this.title.type(text, { delay });
|
||||
});
|
||||
}
|
||||
@@ -196,6 +199,16 @@ export class EditorModel {
|
||||
return tags;
|
||||
}
|
||||
|
||||
async removeTags(tags: string[]) {
|
||||
for (const tag of tags) {
|
||||
const item = this.tags
|
||||
.filter({ hasText: tag })
|
||||
.getByTitle("Remove")
|
||||
.first();
|
||||
await item.click();
|
||||
}
|
||||
}
|
||||
|
||||
async getTitle() {
|
||||
return this.title.inputValue();
|
||||
}
|
||||
|
||||
@@ -28,25 +28,22 @@ export class ItemsViewModel extends BaseViewModel {
|
||||
private readonly createButton: Locator;
|
||||
constructor(page: Page) {
|
||||
super(page, "tags", "tags");
|
||||
this.createButton = page.locator(getTestId(`tags-action-button`));
|
||||
this.createButton = page.locator(getTestId(`create-tag-button`));
|
||||
}
|
||||
|
||||
async createItem(item: Item) {
|
||||
const titleToCompare = `#${item.title}`;
|
||||
|
||||
await this.createButton.first().click();
|
||||
await fillItemDialog(this.page, item);
|
||||
|
||||
await this.waitForItem(titleToCompare);
|
||||
await this.waitForItem(item.title);
|
||||
return await this.findItem(item);
|
||||
}
|
||||
|
||||
async findItem(item: Item) {
|
||||
const titleToCompare = `#${item.title}`;
|
||||
for await (const _item of this.iterateItems()) {
|
||||
const itemModel = new ItemModel(_item, "tag");
|
||||
const title = await itemModel.getTitle();
|
||||
if (title === titleToCompare) return itemModel;
|
||||
if (title === item.title) return itemModel;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -134,14 +134,14 @@ abstract class BaseProperties {
|
||||
|
||||
export class NotePropertiesModel extends BaseProperties {
|
||||
private readonly propertiesButton: Locator;
|
||||
private readonly propertiesCloseButton: Locator;
|
||||
private readonly generalSection: Locator;
|
||||
private readonly readonlyToggle: ToggleModel;
|
||||
private readonly sessionItems: Locator;
|
||||
|
||||
constructor(page: Page, noteLocator: Locator) {
|
||||
super(page, noteLocator, "properties");
|
||||
this.propertiesButton = page.locator(getTestId("Properties"));
|
||||
this.propertiesCloseButton = page.locator(getTestId("properties-close"));
|
||||
this.generalSection = page.locator(getTestId("general-section"));
|
||||
this.readonlyToggle = new ToggleModel(page, `properties-readonly`);
|
||||
this.sessionItems = page.locator(getTestId("session-item"));
|
||||
}
|
||||
@@ -183,12 +183,11 @@ export class NotePropertiesModel extends BaseProperties {
|
||||
|
||||
async open() {
|
||||
await this.propertiesButton.click();
|
||||
await this.propertiesCloseButton.waitFor();
|
||||
await this.page.waitForTimeout(1000);
|
||||
await this.generalSection.waitFor();
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.propertiesCloseButton.click();
|
||||
await this.propertiesButton.click();
|
||||
}
|
||||
|
||||
async getSessionHistory() {
|
||||
|
||||
@@ -25,21 +25,21 @@ import { Notebook } from "./types";
|
||||
import { confirmDialog, fillNotebookDialog } from "./utils";
|
||||
import { NotesViewModel } from "./notes-view.model";
|
||||
import { getTestId } from "../utils";
|
||||
import { SubnotebooksViewModel } from "./subnotebooks-view.model";
|
||||
import { NotebooksViewModel } from "./notebooks-view.model";
|
||||
|
||||
export class NotebookItemModel extends BaseItemModel {
|
||||
private readonly contextMenu: ContextMenuModel;
|
||||
constructor(locator: Locator) {
|
||||
constructor(
|
||||
locator: Locator,
|
||||
private readonly notebooks: NotebooksViewModel
|
||||
) {
|
||||
super(locator);
|
||||
this.contextMenu = new ContextMenuModel(this.page);
|
||||
}
|
||||
|
||||
async openNotebook() {
|
||||
await this.locator.click();
|
||||
return {
|
||||
subNotebooks: new SubnotebooksViewModel(this.page),
|
||||
notes: new NotesViewModel(this.page, "notebook", "notes")
|
||||
};
|
||||
return new NotesViewModel(this.page, "notebook", "notes");
|
||||
}
|
||||
|
||||
async editNotebook(notebook: Notebook) {
|
||||
@@ -49,6 +49,16 @@ export class NotebookItemModel extends BaseItemModel {
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
}
|
||||
|
||||
async createSubnotebook(notebook: Notebook) {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("add");
|
||||
|
||||
await fillNotebookDialog(this.page, notebook);
|
||||
|
||||
await this.notebooks.waitForItem(notebook.title);
|
||||
return await this.notebooks.findNotebook(notebook);
|
||||
}
|
||||
|
||||
async moveToTrash(deleteContainedNotes = false) {
|
||||
await this.contextMenu.open(this.locator);
|
||||
await this.contextMenu.clickOnItem("movetotrash");
|
||||
|
||||
@@ -30,7 +30,7 @@ export class NotebooksViewModel extends BaseViewModel {
|
||||
constructor(page: Page) {
|
||||
super(page, "notebooks", "notebooks");
|
||||
this.createButton = page
|
||||
.locator(getTestId("notebooks-action-button"))
|
||||
.locator(getTestId("create-notebook-button"))
|
||||
.first();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class NotebooksViewModel extends BaseViewModel {
|
||||
|
||||
async findNotebook(notebook: Partial<Notebook>) {
|
||||
for await (const item of this.iterateItems()) {
|
||||
const notebookModel = new NotebookItemModel(item);
|
||||
const notebookModel = new NotebookItemModel(item, this);
|
||||
if ((await notebookModel.getTitle()) === notebook.title)
|
||||
return notebookModel;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,7 @@ export class NotesViewModel extends BaseViewModel {
|
||||
listType: string
|
||||
) {
|
||||
super(page, pageId, listType);
|
||||
this.createButton = page.locator(
|
||||
// TODO:
|
||||
getTestId(`notes-action-button`)
|
||||
);
|
||||
this.createButton = page.locator(getTestId(`create-new-note`));
|
||||
this.editor = new EditorModel(page);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class RemindersViewModel extends BaseViewModel {
|
||||
constructor(page: Page) {
|
||||
super(page, "reminders", "reminders");
|
||||
this.createButton = page
|
||||
.locator(getTestId("reminders-action-button"))
|
||||
.locator(getTestId("create-reminder-button"))
|
||||
.first();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ export class SettingsViewModel {
|
||||
await confirmDialog(this.page.locator(getTestId("confirm-dialog")));
|
||||
|
||||
await this.page
|
||||
.locator(getTestId("not-logged-in"))
|
||||
.waitFor({ state: "visible" });
|
||||
.locator(getTestId("logged-in"))
|
||||
.waitFor({ state: "hidden" });
|
||||
}
|
||||
|
||||
async getRecoveryKey(password: string) {
|
||||
|
||||
@@ -19,11 +19,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
import { getTestId } from "../utils";
|
||||
import { ContextMenuModel } from "./context-menu.model";
|
||||
|
||||
export class TabItemModel {
|
||||
private readonly closeButton: Locator;
|
||||
constructor(private readonly locator: Locator, page: Page) {
|
||||
readonly contextMenu: TabContextMenuModel;
|
||||
readonly titleElement: Locator;
|
||||
|
||||
constructor(readonly locator: Locator, page: Page) {
|
||||
this.closeButton = locator.locator(getTestId("tab-close-button"));
|
||||
this.contextMenu = new TabContextMenuModel(page, locator);
|
||||
this.titleElement = locator.locator(getTestId("tab-title"));
|
||||
}
|
||||
|
||||
async getId() {
|
||||
@@ -36,7 +42,7 @@ export class TabItemModel {
|
||||
}
|
||||
|
||||
async title() {
|
||||
return this.locator.locator(getTestId("tab-title")).textContent();
|
||||
return this.titleElement.textContent();
|
||||
}
|
||||
|
||||
async isActive() {
|
||||
@@ -48,3 +54,19 @@ export class TabItemModel {
|
||||
return this.closeButton.click();
|
||||
}
|
||||
}
|
||||
|
||||
class TabContextMenuModel {
|
||||
private readonly menu: ContextMenuModel;
|
||||
constructor(page: Page, private readonly tabLocator: Locator) {
|
||||
this.menu = new ContextMenuModel(page);
|
||||
}
|
||||
|
||||
async pin() {
|
||||
await this.open();
|
||||
await this.menu.clickOnItem("pin");
|
||||
}
|
||||
|
||||
async open() {
|
||||
await this.menu.open(this.tabLocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,9 @@ function createRoute(key: string, header: string) {
|
||||
|
||||
const routes = [
|
||||
createRoute("notes", "Notes"),
|
||||
createRoute("notebooks", "Notebooks"),
|
||||
createRoute("favorites", "Favorites"),
|
||||
createRoute("monographs", "Monographs"),
|
||||
createRoute("reminders", "Reminders"),
|
||||
createRoute("tags", "Tags"),
|
||||
createRoute("trash", "Trash")
|
||||
];
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ test("create a note inside a notebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const { notes } = (await notebook?.openNotebook()) || {};
|
||||
const notes = await notebook?.openNotebook();
|
||||
await notes?.waitForList();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
|
||||
@@ -55,11 +56,10 @@ test("create a note inside a subnotebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
const { subNotebooks } = (await notebook?.openNotebook()) || {};
|
||||
const subNotebook = await subNotebooks?.createNotebook({
|
||||
const subNotebook = await notebook?.createSubnotebook({
|
||||
title: "Subnotebook 1"
|
||||
});
|
||||
const { notes } = (await subNotebook?.openNotebook()) || {};
|
||||
const notes = await subNotebook?.openNotebook();
|
||||
|
||||
const note = await notes?.createNote(NOTE);
|
||||
|
||||
@@ -80,7 +80,6 @@ test("edit a notebook", async ({ page }) => {
|
||||
|
||||
const editedNotebook = await notebooks.findNotebook(item);
|
||||
expect(editedNotebook).toBeDefined();
|
||||
expect(await editedNotebook?.getDescription()).toBe(item.description);
|
||||
});
|
||||
|
||||
test("delete a notebook", async ({ page }) => {
|
||||
@@ -129,29 +128,6 @@ test("permanently delete a notebook", async ({ page }) => {
|
||||
await expect(trashItem.locator).toBeHidden();
|
||||
});
|
||||
|
||||
test("pin a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
|
||||
await notebook?.pin();
|
||||
|
||||
expect(await notebook?.isPinned()).toBe(true);
|
||||
});
|
||||
|
||||
test("unpin a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
await notebook?.pin();
|
||||
|
||||
await notebook?.unpin();
|
||||
|
||||
expect(await notebook?.isPinned()).toBe(false);
|
||||
});
|
||||
|
||||
test("create shortcut of a notebook", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
@@ -161,8 +137,8 @@ test("create shortcut of a notebook", async ({ page }) => {
|
||||
await notebook?.createShortcut();
|
||||
|
||||
expect(await notebook?.isShortcut()).toBe(true);
|
||||
const allShortcuts = await app.navigation.getShortcuts();
|
||||
expect(allShortcuts.includes(NOTEBOOK.title)).toBeTruthy();
|
||||
await app.goToHome();
|
||||
expect(await app.navigation.findItem(NOTEBOOK.title)).toBeDefined();
|
||||
});
|
||||
|
||||
test("remove shortcut of a notebook", async ({ page }) => {
|
||||
@@ -184,14 +160,13 @@ test("delete all notes within a notebook", async ({ page }) => {
|
||||
await app.goto();
|
||||
const notebooks = await app.goToNotebooks();
|
||||
const notebook = await notebooks.createNotebook(NOTEBOOK);
|
||||
let { notes } = (await notebook?.openNotebook()) || {};
|
||||
let notes = await notebook?.openNotebook();
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
await notes?.createNote({
|
||||
title: `Note ${i}`,
|
||||
content: NOTE.content
|
||||
});
|
||||
}
|
||||
await app.goBack();
|
||||
|
||||
await notebook?.moveToTrash(true);
|
||||
|
||||
@@ -254,20 +229,17 @@ test(`sort notebooks`, async ({ page }, info) => {
|
||||
await notebooks.createNotebook(NOTEBOOK);
|
||||
}
|
||||
|
||||
for (const groupBy of groupByOptions) {
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`group by ${groupBy}, sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await notebooks?.sort({
|
||||
groupBy,
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(notebooks.items).toHaveCount(titles.length);
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await notebooks?.sort({
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
}
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(notebooks.items).toHaveCount(titles.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { createHistorySession } from "./utils";
|
||||
import { createHistorySession, NOTE } from "./utils";
|
||||
|
||||
test("notes should open in the same tab", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
@@ -63,7 +63,7 @@ test("open note in new tab (using context menu)", async ({ page }) => {
|
||||
|
||||
const tabs = await notes.editor.getTabs();
|
||||
expect(tabs.length).toBe(2);
|
||||
expect(await tabs[1].title()).toBe("Note 2");
|
||||
await expect(tabs[1].titleElement).toHaveText("Note 2");
|
||||
});
|
||||
|
||||
test("open note in new tab (using middle click)", async ({ page }) => {
|
||||
@@ -80,7 +80,7 @@ test("open note in new tab (using middle click)", async ({ page }) => {
|
||||
|
||||
const tabs = await notes.editor.getTabs();
|
||||
expect(tabs.length).toBe(2);
|
||||
expect(await tabs[1].title()).toBe("Note 2");
|
||||
await expect(tabs[1].titleElement).toHaveText("Note 2");
|
||||
});
|
||||
|
||||
test("go back should open previous note", async ({ page }) => {
|
||||
@@ -93,9 +93,9 @@ test("go back should open previous note", async ({ page }) => {
|
||||
await notes.createNote({ title: "Note 3" });
|
||||
|
||||
await notes.editor.goBack();
|
||||
expect(await tabs[0].title()).toBe("Note 2");
|
||||
await expect(tabs[0].titleElement).toHaveText("Note 2");
|
||||
await notes.editor.goBack();
|
||||
expect(await tabs[0].title()).toBe("Note 1");
|
||||
await expect(tabs[0].titleElement).toHaveText("Note 1");
|
||||
});
|
||||
|
||||
test("go forward should open next note", async ({ page }) => {
|
||||
@@ -110,9 +110,9 @@ test("go forward should open next note", async ({ page }) => {
|
||||
await notes.editor.goBack();
|
||||
await notes.editor.goBack();
|
||||
await notes.editor.goForward();
|
||||
expect(await tabs[0].title()).toBe("Note 2");
|
||||
await expect(tabs[0].titleElement).toHaveText("Note 2");
|
||||
await notes.editor.goForward();
|
||||
expect(await tabs[0].title()).toBe("Note 3");
|
||||
await expect(tabs[0].titleElement).toHaveText("Note 3");
|
||||
});
|
||||
|
||||
test("new tab button should open a new tab", async ({ page }) => {
|
||||
@@ -124,11 +124,11 @@ test("new tab button should open a new tab", async ({ page }) => {
|
||||
await notes.editor.newTab();
|
||||
|
||||
const tabs = await notes.editor.getTabs();
|
||||
expect(await tabs[0].title()).toBe("Note 1");
|
||||
expect(await tabs[1].title()).toBe("Untitled");
|
||||
await expect(tabs[0].titleElement).toHaveText("Note 1");
|
||||
await expect(tabs[1].titleElement).toHaveText("Untitled");
|
||||
});
|
||||
|
||||
test("changes in a note opened in multiple tabs should sync", async ({
|
||||
test("content changes in a note opened in multiple tabs should sync", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
@@ -173,6 +173,7 @@ test("reloading with a note diff open in a tab", async ({ page }) => {
|
||||
const history = await note?.properties.getSessionHistory();
|
||||
const preview = await history?.[0].open();
|
||||
await preview!.firstEditor.waitFor({ state: "visible" });
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.reload();
|
||||
await preview!.firstEditor.waitFor({ state: "visible" });
|
||||
@@ -227,7 +228,7 @@ test("clicking on a note that's already opened in another tab should focus the t
|
||||
await note?.openNote();
|
||||
|
||||
const tabs = await notes.editor.getTabs();
|
||||
expect(await tabs[0].isActive()).toBe(true);
|
||||
await expect(tabs[0].locator).toHaveClass(/active/);
|
||||
});
|
||||
|
||||
test("open a note in 2 tabs then open another note and navigate back", async ({
|
||||
@@ -248,8 +249,134 @@ test("open a note in 2 tabs then open another note and navigate back", async ({
|
||||
await notes.editor.goBack();
|
||||
|
||||
const tabs = await notes.editor.getTabs();
|
||||
expect(await tabs[1].isActive()).toBe(true);
|
||||
expect(await tabs[1].title()).toBe("Note 1");
|
||||
await expect(tabs[1].locator).toHaveClass(/active/);
|
||||
await expect(tabs[1].titleElement).toHaveText("Note 1");
|
||||
});
|
||||
|
||||
test("shouldn't be possible to open a note in a pinned tab", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote({
|
||||
title: "Note 1"
|
||||
});
|
||||
await notes.createNote({
|
||||
title: "Note 2"
|
||||
});
|
||||
let tabs = await notes.editor.getTabs();
|
||||
await tabs[0].contextMenu.pin();
|
||||
|
||||
await note?.click();
|
||||
await notes.editor.waitForLoading();
|
||||
|
||||
tabs = await notes.editor.getTabs();
|
||||
expect(tabs.length).toBe(2);
|
||||
await expect(tabs[1].locator).toHaveClass(/active/);
|
||||
await expect(tabs[1].titleElement).toHaveText("Note 1");
|
||||
});
|
||||
|
||||
test("shouldn't be possible to create a new note in a pinned tab", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
await notes.createNote({
|
||||
title: "Note 1"
|
||||
});
|
||||
let tabs = await notes.editor.getTabs();
|
||||
await tabs[0].contextMenu.pin();
|
||||
|
||||
await notes.newNote();
|
||||
|
||||
tabs = await notes.editor.getTabs();
|
||||
expect(tabs.length).toBe(2);
|
||||
await expect(tabs[1].locator).toHaveClass(/active/);
|
||||
});
|
||||
|
||||
test("notes open in multiple tabs should sync tags when tags are added", async ({
|
||||
page
|
||||
}) => {
|
||||
const tags = ["toAdd", "todo"];
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.openInNewTab();
|
||||
|
||||
await notes.editor.setTags(tags);
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].click();
|
||||
|
||||
const noteTags = await notes.editor.getTags();
|
||||
expect(noteTags).toHaveLength(tags.length);
|
||||
expect(noteTags.every((t, i) => t === tags[i])).toBe(true);
|
||||
});
|
||||
|
||||
test("notes open in multiple tabs should sync tags when tags are removed", async ({
|
||||
page
|
||||
}) => {
|
||||
const tags = ["removeme", "dontremoveme", "removemex2", "todo"];
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await notes.editor.setTags(tags);
|
||||
await note?.contextMenu.openInNewTab();
|
||||
|
||||
await notes.editor.removeTags(["removeme", "removemex2"]);
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].click();
|
||||
|
||||
const noteTags = await notes.editor.getTags();
|
||||
expect(noteTags).toHaveLength(2);
|
||||
expect(noteTags.every((t, i) => t === ["dontremoveme", "todo"][i])).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test("notes open in multiple tabs should sync color in note properties when color is changed", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await note?.contextMenu.newColor({ title: "red", color: "#ff0000" });
|
||||
await note?.contextMenu.newColor({ title: "blue", color: "#0000ff" });
|
||||
await note?.contextMenu.openInNewTab();
|
||||
|
||||
await notes.editor.waitForLoading();
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].click();
|
||||
|
||||
expect(await note?.properties.isColored("blue")).toBe(true);
|
||||
|
||||
await note?.properties.color("red");
|
||||
await tabs[1].click();
|
||||
|
||||
expect(await note?.properties.isColored("red")).toBe(true);
|
||||
});
|
||||
|
||||
test("notes open in multiple tabs should sync title when title is changed", async ({
|
||||
page
|
||||
}) => {
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
const notes = await app.goToNotes();
|
||||
const note = await notes.createNote(NOTE);
|
||||
await notes.editor.setTitle("Todo");
|
||||
await note?.contextMenu.openInNewTab();
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Todo");
|
||||
|
||||
await notes.editor.setTitle("Todo - Today");
|
||||
const tabs = await notes.editor.getTabs();
|
||||
await tabs[0].click();
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Todo - Today");
|
||||
});
|
||||
|
||||
test.skip("TODO: open a locked note, switch to another note and navigate back", () => {});
|
||||
|
||||
@@ -99,8 +99,8 @@ test("create shortcut of a tag", async ({ page }) => {
|
||||
await tag?.createShortcut();
|
||||
|
||||
expect(await tag?.isShortcut()).toBe(true);
|
||||
const allShortcuts = await app.navigation.getShortcuts();
|
||||
expect(allShortcuts.includes("hello-world")).toBeTruthy();
|
||||
await app.goToHome();
|
||||
expect(await app.navigation.findItem("hello-world")).toBeDefined();
|
||||
});
|
||||
|
||||
test("remove shortcut of a tag", async ({ page }) => {
|
||||
@@ -204,20 +204,17 @@ test(`sort tags`, async ({ page }, info) => {
|
||||
if (!tag) continue;
|
||||
}
|
||||
|
||||
for (const groupBy of groupByOptions) {
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`group by ${groupBy}, sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await tags?.sort({
|
||||
groupBy,
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(tags.items).toHaveCount(titles.length);
|
||||
for (const sortBy of sortByOptions) {
|
||||
for (const orderBy of orderByOptions) {
|
||||
await test.step(`sort by ${sortBy}, order by ${orderBy}`, async () => {
|
||||
const sortResult = await tags?.sort({
|
||||
orderBy,
|
||||
sortBy
|
||||
});
|
||||
}
|
||||
if (!sortResult) return;
|
||||
|
||||
await expect(tags.items).toHaveCount(titles.length);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ The flow will be as follows:
|
||||
5. Use the database password to init the db & keep the user's encryption key in memory. (we have 2 choices here: either keep the encryption key in memory or keep the pin in memory)
|
||||
6. If not enabled, we will ask the keystore to give us the database password + user's encryption key
|
||||
|
||||
We should store both the database password and the user's encryption key in a keychain. If user sets a pin, we can just double encrypt these values. This will keep things simple and seemless.
|
||||
We should store both the database password and the user's encryption key in a keychain. If user sets a pin, we can just double encrypt these values. This will keep things simple and seamless.
|
||||
|
||||
Q: How to find out if app lock is enabled?
|
||||
|
||||
|
||||
57
apps/web/functions/_middleware.ts
Normal file
57
apps/web/functions/_middleware.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
function isBeta(cookie: string) {
|
||||
console.log("Checking cookie:", cookie);
|
||||
const releaseTrack = cookie
|
||||
.split("; ")
|
||||
.find((row) => row.startsWith("release-track="))
|
||||
?.split("=")[1];
|
||||
return releaseTrack === "beta";
|
||||
}
|
||||
|
||||
interface Env {
|
||||
BETA_BASE_URL: string;
|
||||
}
|
||||
|
||||
export const onRequest: PagesFunction<Env> = async ({ request, env, next }) => {
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const response = await (async () => {
|
||||
if (isBeta(request.headers.get("Cookie") || "") && env.BETA_BASE_URL) {
|
||||
const betaUrl = new URL(env.BETA_BASE_URL);
|
||||
betaUrl.pathname = url.pathname;
|
||||
betaUrl.search = url.search;
|
||||
console.log("Fetching asset from beta URL:", betaUrl.toString());
|
||||
const asset = await fetch(betaUrl, {
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
body: request.body
|
||||
});
|
||||
return new Response(asset.body, asset);
|
||||
} else {
|
||||
return await next();
|
||||
}
|
||||
})();
|
||||
return response;
|
||||
} catch (thrown) {
|
||||
console.error("Error occurred:", thrown);
|
||||
return new Response(thrown);
|
||||
}
|
||||
};
|
||||
10
apps/web/functions/tsconfig.json
Normal file
10
apps/web/functions/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"lib": ["ES2020"],
|
||||
"types": ["@cloudflare/workers-types"],
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
21
apps/web/package-lock.json
generated
21
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
@@ -77,7 +77,7 @@
|
||||
"react-modal": "3.16.3",
|
||||
"react-qrcode-logo": "^2.9.0",
|
||||
"react-scroll-sync": "^0.11.2",
|
||||
"react-virtuoso": "^4.6.2",
|
||||
"react-virtuoso": "^4.12.3",
|
||||
"snarkdown": "^2.0.0",
|
||||
"timeago.js": "4.0.2",
|
||||
"w3c-keyname": "^2.2.6",
|
||||
@@ -87,6 +87,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.22.5",
|
||||
"@cloudflare/workers-types": "^4.20250224.0",
|
||||
"@playwright/test": "1.48.2",
|
||||
"@swc/plugin-react-remove-properties": "^6.0.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
@@ -295,6 +296,7 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@notesnook-importer/core": "^2.1.1",
|
||||
"@notesnook/common": "file:../common",
|
||||
"@notesnook/intl": "file:../intl",
|
||||
"@notesnook/theme": "file:../theme",
|
||||
@@ -497,7 +499,7 @@
|
||||
},
|
||||
"../desktop": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.0.25",
|
||||
"version": "3.0.29",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
@@ -506,7 +508,7 @@
|
||||
"@trpc/client": "10.45.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
"better-sqlite3-multiple-ciphers": "11.5.0",
|
||||
"electron-trpc": "0.6.1",
|
||||
"electron-trpc": "0.7.1",
|
||||
"electron-updater": "^6.3.4",
|
||||
"icojs": "^0.19.4",
|
||||
"sqlite-better-trigram": "0.0.2",
|
||||
@@ -529,7 +531,7 @@
|
||||
"slugify": "1.6.6",
|
||||
"tree-kill": "^1.2.2",
|
||||
"undici": "^6.19.8",
|
||||
"vitest": "2.1.8"
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"dmg-license": "^1.0.11"
|
||||
@@ -2132,6 +2134,13 @@
|
||||
"pnpm": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/@cloudflare/workers-types": {
|
||||
"version": "4.20250224.0",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20250224.0.tgz",
|
||||
"integrity": "sha512-j6ZwQ5G2moQRaEtGI2u5TBQhVXv/XwOS5jfBAheZHcpCM07zm8j0i8jZHHLq/6VA8e6VRjKohOyj5j6tZ1KHLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0"
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.0.25",
|
||||
"version": "3.1.0-beta.1",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
@@ -75,7 +75,7 @@
|
||||
"react-modal": "3.16.3",
|
||||
"react-qrcode-logo": "^2.9.0",
|
||||
"react-scroll-sync": "^0.11.2",
|
||||
"react-virtuoso": "^4.6.2",
|
||||
"react-virtuoso": "^4.12.3",
|
||||
"snarkdown": "^2.0.0",
|
||||
"timeago.js": "4.0.2",
|
||||
"w3c-keyname": "^2.2.6",
|
||||
@@ -85,6 +85,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.22.5",
|
||||
"@cloudflare/workers-types": "^4.20250224.0",
|
||||
"@playwright/test": "1.48.2",
|
||||
"@swc/plugin-react-remove-properties": "^6.0.2",
|
||||
"@trpc/server": "10.45.2",
|
||||
@@ -131,6 +132,7 @@
|
||||
"start:test": "serve -s build/ -p 3000",
|
||||
"build": "cross-env PLATFORM=web vite build",
|
||||
"build:test": "cross-env PLATFORM=web TEST=true vite build",
|
||||
"build:beta": "cross-env PLATFORM=web BETA=true vite build",
|
||||
"build:desktop": "cross-env PLATFORM=desktop vite build",
|
||||
"analyze": "cross-env ANALYZING=true PLATFORM=web vite build",
|
||||
"test": "playwright test -u",
|
||||
|
||||
@@ -48,11 +48,9 @@ import { AnnouncementDialog } from "./dialogs/announcement-dialog";
|
||||
import { logger } from "./utils/logger";
|
||||
import { strings } from "@notesnook/intl";
|
||||
|
||||
type AppEffectsProps = {
|
||||
setShow: (show: boolean) => void;
|
||||
};
|
||||
export default function AppEffects({ setShow }: AppEffectsProps) {
|
||||
export default function AppEffects() {
|
||||
const refreshNavItems = useStore((store) => store.refreshNavItems);
|
||||
const toggleListPane = useStore((store) => store.toggleListPane);
|
||||
const updateLastSynced = useStore((store) => store.updateLastSynced);
|
||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||
const initUser = useUserStore((store) => store.init);
|
||||
@@ -234,7 +232,7 @@ export default function AppEffects({ setShow }: AppEffectsProps) {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setShow(!isFocusMode);
|
||||
toggleListPane(!isFocusMode);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isFocusMode]);
|
||||
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
:root {
|
||||
--sash-size: 10px;
|
||||
--sash-hover-size: 4px;
|
||||
}
|
||||
|
||||
.tabsScroll,
|
||||
.titlebarLogo,
|
||||
.theme-scope-titleBar,
|
||||
@@ -18,101 +13,77 @@
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
/* open-sans-regular - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-regular.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-regular.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-regular.ttf")
|
||||
format("truetype");
|
||||
src: local(""), url("./assets/fonts/Inter-Regular.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-Regular.ttf") format("truetype");
|
||||
}
|
||||
/* open-sans-600 - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600.ttf")
|
||||
format("truetype");
|
||||
src: local(""), url("./assets/fonts/Inter-SemiBold.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-SemiBold.ttf") format("truetype");
|
||||
}
|
||||
/* open-sans-700 - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700.ttf")
|
||||
format("truetype");
|
||||
font-weight: 700;
|
||||
src: local(""), url("./assets/fonts/Inter-Bold.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-Bold.ttf") format("truetype");
|
||||
}
|
||||
/* open-sans-italic - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 500;
|
||||
src: local(""), url("./assets/fonts/Inter-Medium.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-Medium.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-italic.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-italic.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-italic.ttf")
|
||||
format("truetype");
|
||||
src: local(""), url("./assets/fonts/Inter-Italic.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-Italic.ttf") format("truetype");
|
||||
}
|
||||
/* open-sans-600italic - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600italic.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600italic.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600italic.ttf")
|
||||
format("truetype");
|
||||
url("./assets/fonts/Inter-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-SemiBoldItalic.ttf") format("truetype");
|
||||
}
|
||||
/* open-sans-700italic - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local(""),
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700italic.woff2")
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700italic.woff")
|
||||
format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("./assets/fonts/open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-700italic.ttf")
|
||||
format("truetype");
|
||||
font-weight: 700;
|
||||
src: local(""), url("./assets/fonts/Inter-BoldItalic.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-BoldItalic.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
font-weight: 500;
|
||||
src: local(""), url("./assets/fonts/Inter-MediumItalic.woff2") format("woff2"),
|
||||
url("./assets/fonts/Inter-MediumItalic.ttf") format("truetype");
|
||||
}
|
||||
|
||||
.rpv-core__text-layer,
|
||||
@@ -249,3 +220,26 @@ textarea,
|
||||
background-color: color-mix(in srgb, var(--accent) 5%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
kbd {
|
||||
background: var(--background);
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
color: var(--paragraph-secondary);
|
||||
}
|
||||
|
||||
.ping {
|
||||
animation: ping 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes ping {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,12 @@ import { AppEventManager, AppEvents } from "./common/app-events";
|
||||
import { TITLE_BAR_HEIGHT } from "./components/title-bar";
|
||||
import { getFontSizes } from "@notesnook/theme/theme/font/fontsize.js";
|
||||
import { useWindowControls } from "./hooks/use-window-controls";
|
||||
import { STATUS_BAR_HEIGHT } from "./common/constants";
|
||||
|
||||
new WebExtensionRelay();
|
||||
|
||||
function App() {
|
||||
const isMobile = useMobile();
|
||||
const [show, setShow] = useState(true);
|
||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||
const { isFocused } = useWindowFocus();
|
||||
const { isFullscreen } = useWindowControls();
|
||||
@@ -67,9 +67,6 @@ function App() {
|
||||
.nav-pane {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.titlebar {
|
||||
background: var(--background-secondary) !important;
|
||||
}
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
@@ -77,15 +74,9 @@ function App() {
|
||||
<Global
|
||||
// These styles to make sure the app content doesn't overlap with the traffic lights.
|
||||
styles={`
|
||||
.nav-pane,
|
||||
.mobile-nav-pane {
|
||||
margin-top: env(titlebar-area-height) !important;
|
||||
height: calc(100% - env(titlebar-area-height)) !important;
|
||||
}
|
||||
.nav-pane.collapsed + .list-pane .route-container-header,
|
||||
.nav-pane.collapsed + .list-pane.collapsed + .editor-pane .editor-action-bar,
|
||||
.nav-pane.collapsed + .editor-pane .editor-action-bar {
|
||||
padding-left: 25px;
|
||||
.nav-pane .theme-scope-navigationMenu,
|
||||
.mobile-nav-pane .theme-scope-navigationMenu {
|
||||
padding-top: env(titlebar-area-height) !important;
|
||||
}
|
||||
.editor-pane:first-of-type .editor-action-bar,
|
||||
.mobile-editor-pane.pane-active .editor-action-bar,
|
||||
@@ -101,9 +92,9 @@ function App() {
|
||||
.route-container-header .routeHeader {
|
||||
font-size: ${getFontSizes().title};
|
||||
}
|
||||
.global-split-pane .react-split__sash {
|
||||
height: calc(100% - ${TITLE_BAR_HEIGHT}px);
|
||||
}
|
||||
// .global-split-pane .react-split__sash {
|
||||
// height: calc(100% - ${TITLE_BAR_HEIGHT}px);
|
||||
// }
|
||||
`}
|
||||
/>
|
||||
) : null}
|
||||
@@ -113,7 +104,7 @@ function App() {
|
||||
<GlobalMenuWrapper />
|
||||
</div>
|
||||
</Suspense>
|
||||
<AppEffects setShow={setShow} />
|
||||
<AppEffects />
|
||||
|
||||
<Flex
|
||||
id="app"
|
||||
@@ -125,12 +116,11 @@ function App() {
|
||||
height: "100%"
|
||||
}}
|
||||
>
|
||||
{isMobile ? (
|
||||
<MobileAppContents />
|
||||
) : (
|
||||
<DesktopAppContents setShow={setShow} show={show} />
|
||||
)}
|
||||
<Toaster containerClassName="toasts-container" />
|
||||
{isMobile ? <MobileAppContents /> : <DesktopAppContents />}
|
||||
<Toaster
|
||||
containerClassName="toasts-container"
|
||||
containerStyle={{ bottom: STATUS_BAR_HEIGHT + 10 }}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
@@ -138,14 +128,11 @@ function App() {
|
||||
|
||||
export default App;
|
||||
|
||||
type DesktopAppContentsProps = {
|
||||
show: boolean;
|
||||
setShow: (show: boolean) => void;
|
||||
};
|
||||
function DesktopAppContents({ show, setShow }: DesktopAppContentsProps) {
|
||||
function DesktopAppContents() {
|
||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||
const isListPaneVisible = useStore((store) => store.isListPaneVisible);
|
||||
const isTablet = useTablet();
|
||||
const [isNarrow, setIsNarrow] = useState(isTablet || false);
|
||||
// const [isNarrow, setIsNarrow] = useState(isTablet || false);
|
||||
const navPane = useRef<SplitPaneImperativeHandle>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -167,27 +154,26 @@ function DesktopAppContents({ show, setShow }: DesktopAppContentsProps) {
|
||||
autoSaveId="global-panel-group"
|
||||
direction="vertical"
|
||||
onChange={(sizes) => {
|
||||
setIsNarrow(sizes[0] <= 70);
|
||||
useStore.setState({ isNavPaneCollapsed: sizes[0] <= 70 });
|
||||
}}
|
||||
>
|
||||
{isFocusMode ? null : (
|
||||
<Pane
|
||||
id="nav-pane"
|
||||
initialSize={180}
|
||||
initialSize={isTablet ? 0 : 250}
|
||||
className={`nav-pane`}
|
||||
snapSize={160}
|
||||
minSize={50}
|
||||
snapSize={120}
|
||||
maxSize={300}
|
||||
maxSize={isTablet ? 0 : 500}
|
||||
style={{
|
||||
overflow: "initial",
|
||||
zIndex: 3
|
||||
}}
|
||||
>
|
||||
<NavigationMenu
|
||||
toggleNavigationContainer={(state) => {
|
||||
setShow(state || !show);
|
||||
}}
|
||||
isTablet={isNarrow}
|
||||
/>
|
||||
<NavigationMenu onExpand={() => navPane.current?.reset(0)} />
|
||||
</Pane>
|
||||
)}
|
||||
{!isFocusMode && show ? (
|
||||
{!isFocusMode && isListPaneVisible ? (
|
||||
<Pane
|
||||
id="list-pane"
|
||||
initialSize={380}
|
||||
@@ -297,7 +283,7 @@ function MobileAppContents() {
|
||||
flexShrink: 0
|
||||
}}
|
||||
>
|
||||
<NavigationMenu toggleNavigationContainer={() => {}} isTablet={false} />
|
||||
<NavigationMenu />
|
||||
</Flex>
|
||||
<Flex
|
||||
className="mobile-list-pane"
|
||||
|
||||
BIN
apps/web/src/assets/fonts/Inter-Bold.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-Bold.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Bold.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-Bold.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-BoldItalic.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-BoldItalic.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Italic.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-Italic.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Italic.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-Italic.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Medium.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-Medium.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Medium.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-Medium.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-MediumItalic.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-MediumItalic.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Regular.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-Regular.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-Regular.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-Regular.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-SemiBold.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-SemiBold.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-SemiBold.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-SemiBold.woff2
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-SemiBoldItalic.ttf
Normal file
BIN
apps/web/src/assets/fonts/Inter-SemiBoldItalic.ttf
Normal file
Binary file not shown.
BIN
apps/web/src/assets/fonts/Inter-SemiBoldItalic.woff2
Normal file
BIN
apps/web/src/assets/fonts/Inter-SemiBoldItalic.woff2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user