Compare commits

...
Author SHA1 Message Date
StandardNotes CI ede3bada2e chore(release): publish
- @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2022-11-04 03:12:44 +00:00
StandardNotes CI a4ca89118b chore(release): components 2022-11-04 03:12:26 +00:00
Mo 8b9a75530c chore: types 2022-11-03 21:33:58 -05:00
Mo b2831963fd chore: types 2022-11-03 21:30:22 -05:00
Mo 0f90db2836 chore: models workspace deps to devDeps so it can be used externally (skip e2e) 2022-11-03 21:23:49 -05:00
Mo 6759386bef chore: type required by plugins (skip e2e) 2022-11-03 21:20:48 -05:00
Mo 5ed61d1097 chore: fix build script (skip e2e) 2022-11-03 21:04:16 -05:00
Mo 8bb9f4ed11 chore: snjs workspace deps to devDeps so it can be used externally (skip e2e) 2022-11-03 20:58:34 -05:00
Mo 1252375a2e chore: publish packages required by plugins (skip e2e) 2022-11-03 20:43:21 -05:00
StandardNotes CI 1e2542e4f5 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-11-03 20:40:20 +00:00
Aman Harwara 633d6189fb fix: padding on files view on mobile (#1934) 2022-11-04 01:34:47 +05:30
StandardNotes CI 5075b0c85a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-11-03 16:07:18 +00:00
Aman Harwara 2dd0586bb1 fix: archived/trashed items getting unselected when changed (#1932) 2022-11-03 21:04:55 +05:30
StandardNotes CI eab3dc99ed chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-11-03 15:07:49 +00:00
Mo 5bb4435c5b fix: unable to add children to favorited tag; remove expand-on-click; render arrow before title (#1931) 2022-11-03 09:38:31 -05:00
StandardNotes CI 63c10c703f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-11-03 14:04:27 +00:00
Aman Harwara 4036113206 fix: files list not updating when new file is uploaded 2022-11-03 19:02:30 +05:30
Aman Harwara de4adca059 fix: "No modifications allowed" error on file drag in Firefox 2022-11-03 19:00:34 +05:30
Aman Harwara 9ae0ce0bfd fix(desktop): editor column top padding on mac 2022-11-03 18:34:59 +05:30
StandardNotes CI 455cdc01fc chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-11-03 12:20:16 +00:00
Mo c4dbc5cbd2 fix: purchase flow close on complete 2022-11-03 06:46:07 -05:00
Mo 305ffdf984 fix: correctly refresh cta banner 2022-11-03 06:35:06 -05:00
Aman Harwara dc4530b2f3 fix(mobile): disable pinch zoom on mobile app UI 2022-11-03 16:49:32 +05:30
Aman Harwara d6cafa1e73 fix(desktop): selected column top padding on small windows 2022-11-03 16:28:28 +05:30
Aman Harwara ac96e197e0 fix(desktop): only add extra popover padding for small windows 2022-11-03 15:59:48 +05:30
StandardNotes CI 636963b409 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-11-03 09:11:06 +00:00
Karol Sójko 7ead0f655b feat: add sending user requests from UI (#1927)
* feat: add sending user requests from UI

* fix(web): view controller manager user client references
2022-11-03 09:39:38 +01:00
StandardNotes CI 6b50372db2 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-11-02 19:15:23 +00:00
Aman Harwara a6ef658dae feat: prioritize loading latest selected items (#1930) 2022-11-03 00:11:17 +05:30
StandardNotes CI 8c49ca5572 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-11-02 17:36:31 +00:00
Mo 35b21b21ce fix: hide subscription marketing on iOS (#1929) 2022-11-02 12:07:26 -05:00
StandardNotes CI f3e2d80b44 chore(release): publish
- @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
2022-11-02 16:33:43 +00:00
Mo dd821c95e6 feat: dedicated files layout (#1928) 2022-11-02 11:06:19 -05:00
115 changed files with 1576 additions and 529 deletions
-4
View File
@@ -1,4 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn commitlint --edit $1
-2
View File
@@ -1,2 +0,0 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
+2 -2
View File
@@ -22,12 +22,12 @@
"lint": "yarn workspaces foreach -t --verbose --exclude @standardnotes/components-meta run lint",
"test": "yarn workspaces foreach -pt --jobs 10 --verbose --exclude @standardnotes/components-meta run test",
"clean": "lerna run clean",
"build:all": "yarn workspaces foreach -pt --verbose --exclude '{@standardnotes/docs}' run build",
"build:all": "yarn workspaces foreach -pt --topological-dev --verbose --exclude '{@standardnotes/docs}' run build",
"build:components": "yarn workspaces foreach -pt --verbose --interlaced -R --from @standardnotes/components-meta run build",
"build:web": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/web --exclude @standardnotes/components-meta run build",
"build:desktop": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/desktop --exclude @standardnotes/components-meta run build",
"build:mobile": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/mobile --exclude @standardnotes/components-meta run build",
"build:snjs": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/snjs --exclude @standardnotes/components-meta run build",
"build:snjs": "yarn workspaces foreach -p --topological-dev --verbose -R --from @standardnotes/snjs --exclude @standardnotes/components-meta run build",
"build:services": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/services --exclude @standardnotes/components-meta run build",
"build:api": "yarn workspaces foreach -pt --verbose -R --from @standardnotes/api --exclude @standardnotes/components-meta run build",
"start:server:web": "lerna run start --scope=@standardnotes/web",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.19.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/api
## [1.19.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/api
# [1.19.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.19.0",
"version": "1.19.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.7.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/components-meta
+6 -6
View File
@@ -70,9 +70,9 @@
"binary": "b621bfd81829a205f2f02e85d446e277ad20e367b92676ec20b3ee59b1bfab3f"
},
"org.standardnotes.markdown-visual-editor": {
"version": "1.1.5",
"base64": "7aea4cbf43d8cb6411171d09c1cd7e0428d59ab53419b601011ccfeb747426a3",
"binary": "ad75788eee720990203f8443bdc8c0a171ec404ba3462d33f833937d6ba236a4"
"version": "1.1.6",
"base64": "def28b9d33e378b56a610e662951cbbad1cc9313c994c0c099e63b1df8baa2ec",
"binary": "0fb52462d0183397e259afc437c3bd338e1466138505c0fa2179c036a466e505"
},
"org.standardnotes.simple-task-editor": {
"version": "1.4.4",
@@ -80,9 +80,9 @@
"binary": "9df983a144b9686f4f58b03bf78bf1f84f53aea60251621a75586722bf576475"
},
"org.standardnotes.token-vault": {
"version": "2.2.7",
"base64": "fd6ecde33b7135487a60d630813de8f8b4e5e0f06457c7dfda5bee28f3ea1113",
"binary": "88d1401384373ea8bc4b1c4669b34733e24d3692f7aa544b2d6f796de2275703"
"version": "2.2.8",
"base64": "2d91555d9db1aab56d3e3ce15623fb7de14f4efe7d5904bd4db7d081f5991ada",
"binary": "8a7cac8e08d1b18fa2c5a76b8a2a621f0c57b5b71eb9465eaf4de96c89361515"
},
"org.standardnotes.standard-sheets": {
"version": "1.5.1",
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.24",
"version": "2.7.25",
"private": true,
"author": "Standard Notes.",
"main": "dist",
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/markdown-visual
## [1.1.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-01)
**Note:** Version bump only for package @standardnotes/markdown-visual
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/markdown-visual",
"version": "1.1.5",
"version": "1.1.6",
"author": "Johnny Almonte <[email protected]>",
"description": "A lightweight WYSIWYG markdown editor for Standard Notes, derived from Milkdown.",
"keywords": [
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/authenticator
## [2.2.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-01)
**Note:** Version bump only for package @standardnotes/authenticator
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/authenticator",
"version": "2.2.7",
"version": "2.2.8",
"main": "dist/dist.js",
"author": "Standard Notes",
"private": true,
+45
View File
@@ -3,6 +3,51 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.275](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.274](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.273](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.272](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.271](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* **desktop:** editor column top padding on mac ([9ae0ce0](https://github.com/standardnotes/app/commit/9ae0ce0bfd78bedf3e8318aa56b8542dd81d5870))
## [3.23.270](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* **desktop:** only add extra popover padding for small windows ([ac96e19](https://github.com/standardnotes/app/commit/ac96e197e00a7e7af1b771e46a178b0fa21d0f94))
* **desktop:** selected column top padding on small windows ([d6cafa1](https://github.com/standardnotes/app/commit/d6cafa1e739dd46e4cf465d8511aad2024ebe294))
## [3.23.269](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.268](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.267](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.266](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.265](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/desktop
@@ -122,7 +122,7 @@ async function configureWindow(remoteBridge: CrossProcessBridge) {
the app content height so its not overflowing */
sheet.insertRule('body { padding-top: var(--sn-desktop-titlebar-height); }', sheet.cssRules.length)
sheet.insertRule(
'[data-popover] { padding-top: calc(var(--sn-desktop-titlebar-height) + 0.5rem); }',
'@media screen and (max-width: 768px) { [data-popover] { padding-top: calc(var(--sn-desktop-titlebar-height) + 0.5rem); } }',
sheet.cssRules.length,
)
sheet.insertRule(
@@ -9,6 +9,12 @@
transition: 0.15s padding ease;
}
@media screen and (max-width: 768px) {
.mac-desktop .app-column.selected {
padding-top: 18px;
}
}
@media screen and (min-width: 768px) {
.mac-desktop #app.collapsed-notes.collapsed-navigation #editor-column {
padding-top: 18px;
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.265",
"version": "3.23.275",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.19.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/encryption
## [1.19.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/encryption
# [1.19.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.19.0",
"version": "1.19.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.25.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.25.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/filepicker
# [1.25.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.25.0",
"version": "1.25.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.12.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/files
## [1.12.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/files
# [1.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.12.0",
"version": "1.12.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+42
View File
@@ -3,6 +3,48 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.45.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* **mobile:** disable pinch zoom on mobile app UI ([dc4530b](https://github.com/standardnotes/app/commit/dc4530b2f33057ec3d44a94b28dc0407656d4098))
## [3.45.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/mobile
## [3.45.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/mobile
@@ -4,7 +4,7 @@
<head>
<meta charset="utf-8" />
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<meta content="viewport-fit=cover, width=device-width, initial-scale=1" name="viewport" />
<meta content="viewport-fit=cover, width=device-width, initial-scale=1, maximum-scale=1.0" name="viewport" />
<meta content="#ffffff" name="theme-color" />
<link rel="stylesheet" href="web-src/app.css" />
<script>
@@ -23,4 +23,4 @@
<body>
</body>
</html>
</html>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.45.14",
"version": "3.45.24",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.34.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/models
# [1.34.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* dedicated files layout ([#1928](https://github.com/standardnotes/app/issues/1928)) ([dd821c9](https://github.com/standardnotes/app/commit/dd821c95e61c8cd82317ad9fb3788daff7241942))
# [1.33.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+7 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.33.0",
"version": "1.34.4",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -22,21 +22,19 @@
"test": "jest"
},
"devDependencies": {
"@standardnotes/common": "^1.43.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/utils": "workspace:*",
"@types/jest": "^28.1.5",
"@types/lodash": "^4.14.182",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"eslint": "*",
"eslint-plugin-prettier": "*",
"jest": "^28.1.2",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"ts-jest": "^28.0.5",
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.43.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/utils": "workspace:*",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13"
}
}
@@ -0,0 +1,19 @@
import { ItemContent } from './../Content/ItemContent'
import { ContentType } from '@standardnotes/common'
export type OutgoingItemMessagePayload<C extends ItemContent = ItemContent> = {
uuid: string
content_type: ContentType
created_at: Date
updated_at: Date
deleted?: boolean
content?: C
clientData?: Record<string, unknown>
/**
* isMetadataUpdate implies that the extension should make reference of updated
* metadata, but not update content values as they may be stale relative to what the
* extension currently has.
*/
isMetadataUpdate: boolean
}
@@ -17,4 +17,5 @@ export interface TagPreferences {
customNoteTitleFormat?: string
editorIdentifier?: FeatureIdentifier | string
entryMode?: 'normal' | 'daily'
panelWidth?: number
}
+1
View File
@@ -5,6 +5,7 @@ export * from './Abstract/Component/ComponentViewerEvent'
export * from './Abstract/Component/IncomingComponentItemPayload'
export * from './Abstract/Component/KeyboardModifier'
export * from './Abstract/Component/MessageData'
export * from './Abstract/Component/OutgoingItemMessagePayload'
export * from './Abstract/Component/PermissionDialog'
export * from './Abstract/Content/ItemContent'
export * from './Abstract/Contextual/BackupFile'
+40
View File
@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.206](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.205](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.204](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.203](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.202](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.201](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.200](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.199](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.198](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.197](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.196](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.196",
"version": "1.3.206",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/services
# [1.42.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Features
* add sending user requests from UI ([#1927](https://github.com/standardnotes/app/issues/1927)) ([7ead0f6](https://github.com/standardnotes/app/commit/7ead0f655bb2572e5805dd26c297d520949d661a))
# [1.41.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* prioritize loading latest selected items ([#1930](https://github.com/standardnotes/app/issues/1930)) ([a6ef658](https://github.com/standardnotes/app/commit/a6ef658daef9a01f5ddacc967fe30d22f580799a))
## [1.40.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/services
# [1.40.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.40.0",
"version": "1.42.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -38,6 +38,7 @@ export enum StorageKey {
ExperimentalFeatures = 'experimental_features',
DeinitMode = 'deinit_mode',
CodeVerifier = 'code_verifier',
LaunchPriorityUuids = 'launch_priority_uuids',
}
export enum NonwrappedStorageKey {
@@ -1,3 +1,4 @@
import { UserRequestType } from '@standardnotes/common'
import { DeinitSource } from '../Application/DeinitSource'
export interface UserClientInterface {
@@ -6,4 +7,5 @@ export interface UserClientInterface {
message?: string
}>
signOut(force?: boolean, source?: DeinitSource): Promise<void>
submitUserRequest(requestType: UserRequestType): Promise<boolean>
}
@@ -0,0 +1,92 @@
import { UserApiServiceInterface } from '@standardnotes/api'
import { UserRequestType } from '@standardnotes/common'
import { EncryptionProviderInterface } from '@standardnotes/encryption'
import { User } from '@standardnotes/responses'
import {
AlertService,
ChallengeServiceInterface,
InternalEventBusInterface,
ItemManagerInterface,
ProtectionsClientInterface,
} from '..'
import { SessionsClientInterface } from '../Session/SessionsClientInterface'
import { StorageServiceInterface } from '../Storage/StorageServiceInterface'
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
import { UserService } from './UserService'
describe('UserService', () => {
let sessionManager: SessionsClientInterface
let syncService: SyncServiceInterface
let storageService: StorageServiceInterface
let itemManager: ItemManagerInterface
let protocolService: EncryptionProviderInterface
let alertService: AlertService
let challengeService: ChallengeServiceInterface
let protectionService: ProtectionsClientInterface
let userApiService: UserApiServiceInterface
let internalEventBus: InternalEventBusInterface
const createService = () =>
new UserService(
sessionManager,
syncService,
storageService,
itemManager,
protocolService,
alertService,
challengeService,
protectionService,
userApiService,
internalEventBus,
)
beforeEach(() => {
sessionManager = {} as jest.Mocked<SessionsClientInterface>
sessionManager.getSureUser = jest.fn().mockReturnValue({ uuid: '1-2-3' } as jest.Mocked<User>)
syncService = {} as jest.Mocked<SyncServiceInterface>
storageService = {} as jest.Mocked<StorageServiceInterface>
itemManager = {} as jest.Mocked<ItemManagerInterface>
protocolService = {} as jest.Mocked<EncryptionProviderInterface>
alertService = {} as jest.Mocked<AlertService>
challengeService = {} as jest.Mocked<ChallengeServiceInterface>
protectionService = {} as jest.Mocked<ProtectionsClientInterface>
userApiService = {} as jest.Mocked<UserApiServiceInterface>
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
})
it('should submit a user request to the server', async () => {
userApiService.submitUserRequest = jest.fn().mockReturnValue({ data: { success: true } })
expect(await createService().submitUserRequest(UserRequestType.ExitDiscount)).toBeTruthy()
})
it('should indicate error if submit a user request to the server fails', async () => {
userApiService.submitUserRequest = jest.fn().mockReturnValue({ data: { success: false } })
expect(await createService().submitUserRequest(UserRequestType.ExitDiscount)).toBeFalsy()
})
it('should indicate error if submit a user request to the server fails with an error on server side', async () => {
userApiService.submitUserRequest = jest.fn().mockReturnValue({ data: { error: { message: 'fail' } } })
expect(await createService().submitUserRequest(UserRequestType.ExitDiscount)).toBeFalsy()
})
it('should indicate error if submitting a user request throws an exception', async () => {
userApiService.submitUserRequest = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
expect(await createService().submitUserRequest(UserRequestType.ExitDiscount)).toBeFalsy()
})
})
@@ -1,6 +1,6 @@
import { EncryptionProviderInterface, SNRootKey, SNRootKeyParams } from '@standardnotes/encryption'
import { HttpResponse, SignInResponse, User } from '@standardnotes/responses'
import { KeyParamsOrigination } from '@standardnotes/common'
import { KeyParamsOrigination, UserRequestType } from '@standardnotes/common'
import { UuidGenerator } from '@standardnotes/utils'
import { UserApiServiceInterface, UserRegistrationResponseBody } from '@standardnotes/api'
@@ -233,6 +233,24 @@ export class UserService extends AbstractService<AccountEvent, AccountEventData>
}
}
async submitUserRequest(requestType: UserRequestType): Promise<boolean> {
const userUuid = this.sessionManager.getSureUser().uuid
try {
const result = await this.userApiService.submitUserRequest({
userUuid,
requestType,
})
if (result.data.error) {
return false
}
return result.data.success
} catch (error) {
return false
}
}
/**
* A sign in request that occurs while the user was previously signed in, to correct
* for missing keys or storage values. Unlike regular sign in, this doesn't worry about
+18
View File
@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.147.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/snjs
## [2.147.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
**Note:** Version bump only for package @standardnotes/snjs
# [2.147.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* prioritize loading latest selected items ([#1930](https://github.com/standardnotes/app/issues/1930)) ([a6ef658](https://github.com/standardnotes/app/commit/a6ef658daef9a01f5ddacc967fe30d22f580799a))
## [2.146.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/snjs
# [2.146.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
@@ -34,6 +34,7 @@ import {
MessageData,
Environment,
Platform,
OutgoingItemMessagePayload,
} from '@standardnotes/models'
import find from 'lodash/find'
import uniq from 'lodash/uniq'
@@ -41,7 +42,6 @@ import remove from 'lodash/remove'
import { SNSyncService } from '@Lib/Services/Sync/SyncService'
import { environmentToString, platformToString } from '@Lib/Application/Platforms'
import {
OutgoingItemMessagePayload,
MessageReply,
StreamItemsMessageData,
AllowedBatchContentTypes,
@@ -1,25 +1,8 @@
import { ComponentArea, ComponentAction, FeatureIdentifier, LegacyFileSafeIdentifier } from '@standardnotes/features'
import { ComponentMessage, ItemContent, MessageData } from '@standardnotes/models'
import { ComponentMessage, MessageData, OutgoingItemMessagePayload } from '@standardnotes/models'
import { UuidString } from '@Lib/Types/UuidString'
import { ContentType } from '@standardnotes/common'
export type OutgoingItemMessagePayload = {
uuid: string
content_type: ContentType
created_at: Date
updated_at: Date
deleted?: boolean
content?: ItemContent
clientData?: Record<string, unknown>
/**
* isMetadataUpdate implies that the extension should make reference of updated
* metadata, but not update content values as they may be stale relative to what the
* extension currently has.
*/
isMetadataUpdate: boolean
}
/**
* Extensions allowed to batch stream AllowedBatchContentTypes
*/
@@ -35,7 +35,7 @@ export class SNPreferencesService
})
this.removeSyncObserver = syncService.addEventObserver((event) => {
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded) {
if (event === SyncEvent.SyncCompletedWithAllItemsUploaded || event === SyncEvent.LocalDataIncrementalLoad) {
void this.reload()
}
})
@@ -2,6 +2,8 @@ import { SyncOpStatus } from './SyncOpStatus'
import { SyncOptions } from '@standardnotes/services'
export interface SyncClientInterface {
setLaunchPriorityUuids(launchPriorityUuids: string[]): void
sync(options?: Partial<SyncOptions>): Promise<unknown>
isOutOfSync(): boolean
+55 -36
View File
@@ -18,7 +18,7 @@ import { SNHistoryManager } from '../History/HistoryManager'
import { SNLog } from '@Lib/Log'
import { SNSessionManager } from '../Session/SessionManager'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { SortPayloadsByRecentAndContentPriority } from '@Lib/Services/Sync/Utils'
import { GetSortedPayloadsByPriority } from '@Lib/Services/Sync/Utils'
import { SyncClientInterface } from './SyncClientInterface'
import { SyncPromise } from './Types'
import { SyncOpStatus } from '@Lib/Services/Sync/SyncOpStatus'
@@ -56,6 +56,7 @@ import {
PayloadEmitSource,
getIncrementedDirtyIndex,
getCurrentDirtyIndex,
ItemContent,
} from '@standardnotes/models'
import {
AbstractService,
@@ -158,6 +159,14 @@ export class SNSyncService
}
}
private get launchPriorityUuids() {
return this.storageService.getValue<string[]>(StorageKey.LaunchPriorityUuids) ?? []
}
public setLaunchPriorityUuids(launchPriorityUuids: string[]) {
this.storageService.setValue(StorageKey.LaunchPriorityUuids, launchPriorityUuids)
}
public override deinit(): void {
this.dealloced = true
;(this.sessionManager as unknown) = undefined
@@ -272,15 +281,15 @@ export class SNSyncService
})
.filter(isNotUndefined)
const payloads = SortPayloadsByRecentAndContentPriority(unsortedPayloads, this.localLoadPriorty)
const { itemsKeyPayloads, contentTypePriorityPayloads, remainingPayloads } = GetSortedPayloadsByPriority(
unsortedPayloads,
this.localLoadPriorty,
this.launchPriorityUuids,
)
const itemsKeysPayloads = payloads.filter((payload) => {
return payload.content_type === ContentType.ItemsKey
})
await this.processItemsKeysFirstDuringDatabaseLoad(itemsKeyPayloads)
subtractFromArray(payloads, itemsKeysPayloads)
await this.processItemsKeysFirstDuringDatabaseLoad(itemsKeysPayloads)
await this.processPayloadBatch(contentTypePriorityPayloads)
/**
* Map in batches to give interface a chance to update. Note that total decryption
@@ -288,45 +297,55 @@ export class SNSyncService
* batches will result in the same time spent. It's the emitting/painting/rendering
* that requires batch size optimization.
*/
const payloadCount = payloads.length
const payloadCount = remainingPayloads.length
const batchSize = this.options.loadBatchSize
const numBatches = Math.ceil(payloadCount / batchSize)
for (let batchIndex = 0; batchIndex < numBatches; batchIndex++) {
const currentPosition = batchIndex * batchSize
const batch = payloads.slice(currentPosition, currentPosition + batchSize)
const encrypted: EncryptedPayloadInterface[] = []
const nonencrypted: (DecryptedPayloadInterface | DeletedPayloadInterface)[] = []
for (const payload of batch) {
if (isEncryptedPayload(payload)) {
encrypted.push(payload)
} else {
nonencrypted.push(payload)
}
}
const split: KeyedDecryptionSplit = {
usesItemsKeyWithKeyLookup: {
items: encrypted,
},
}
const results = await this.protocolService.decryptSplit(split)
await this.payloadManager.emitPayloads([...nonencrypted, ...results], PayloadEmitSource.LocalDatabaseLoaded)
void this.notifyEvent(SyncEvent.LocalDataIncrementalLoad)
this.opStatus.setDatabaseLoadStatus(currentPosition, payloadCount, false)
await sleep(1, false)
const batch = remainingPayloads.slice(currentPosition, currentPosition + batchSize)
await this.processPayloadBatch(batch, currentPosition, payloadCount)
}
this.databaseLoaded = true
this.opStatus.setDatabaseLoadStatus(0, 0, true)
}
private async processPayloadBatch(
batch: FullyFormedPayloadInterface<ItemContent>[],
currentPosition?: number,
payloadCount?: number,
) {
const encrypted: EncryptedPayloadInterface[] = []
const nonencrypted: (DecryptedPayloadInterface | DeletedPayloadInterface)[] = []
for (const payload of batch) {
if (isEncryptedPayload(payload)) {
encrypted.push(payload)
} else {
nonencrypted.push(payload)
}
}
const split: KeyedDecryptionSplit = {
usesItemsKeyWithKeyLookup: {
items: encrypted,
},
}
const results = await this.protocolService.decryptSplit(split)
await this.payloadManager.emitPayloads([...nonencrypted, ...results], PayloadEmitSource.LocalDatabaseLoaded)
void this.notifyEvent(SyncEvent.LocalDataIncrementalLoad)
if (currentPosition != undefined && payloadCount != undefined) {
this.opStatus.setDatabaseLoadStatus(currentPosition, payloadCount, false)
}
await sleep(1, false)
}
private setLastSyncToken(token: string) {
this.syncToken = token
return this.storageService.setValue(StorageKey.LastSyncToken, token)
@@ -0,0 +1,146 @@
import { ContentType } from '@standardnotes/common'
import { FullyFormedPayloadInterface } from '@standardnotes/models'
import { GetSortedPayloadsByPriority } from './Utils'
describe('GetSortedPayloadsByPriority', () => {
let payloads: FullyFormedPayloadInterface[] = []
const contentTypePriority = [ContentType.ItemsKey, ContentType.UserPrefs, ContentType.Component, ContentType.Theme]
let launchPriorityUuids: string[] = []
it('should sort payloads based on content type priority', () => {
payloads = [
{
content_type: ContentType.Theme,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.UserPrefs,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Component,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.ItemsKey,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Note,
} as FullyFormedPayloadInterface,
]
const { itemsKeyPayloads, contentTypePriorityPayloads, remainingPayloads } = GetSortedPayloadsByPriority(
payloads,
contentTypePriority,
launchPriorityUuids,
)
expect(itemsKeyPayloads.length).toBe(1)
expect(itemsKeyPayloads[0].content_type).toBe(ContentType.ItemsKey)
expect(contentTypePriorityPayloads.length).toBe(3)
expect(contentTypePriorityPayloads[0].content_type).toBe(ContentType.UserPrefs)
expect(contentTypePriorityPayloads[1].content_type).toBe(ContentType.Component)
expect(contentTypePriorityPayloads[2].content_type).toBe(ContentType.Theme)
expect(remainingPayloads.length).toBe(1)
expect(remainingPayloads[0].content_type).toBe(ContentType.Note)
})
it('should sort payloads based on launch priority uuids', () => {
const unprioritizedNoteUuid = 'unprioritized-note'
const unprioritizedTagUuid = 'unprioritized-tag'
const prioritizedNoteUuid = 'prioritized-note'
const prioritizedTagUuid = 'prioritized-tag'
payloads = [
{
content_type: ContentType.Theme,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.UserPrefs,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Component,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.ItemsKey,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Note,
uuid: unprioritizedNoteUuid,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Tag,
uuid: unprioritizedTagUuid,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Note,
uuid: prioritizedNoteUuid,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Tag,
uuid: prioritizedTagUuid,
} as FullyFormedPayloadInterface,
]
launchPriorityUuids = [prioritizedNoteUuid, prioritizedTagUuid]
const { itemsKeyPayloads, contentTypePriorityPayloads, remainingPayloads } = GetSortedPayloadsByPriority(
payloads,
contentTypePriority,
launchPriorityUuids,
)
expect(itemsKeyPayloads.length).toBe(1)
expect(itemsKeyPayloads[0].content_type).toBe(ContentType.ItemsKey)
expect(contentTypePriorityPayloads.length).toBe(3)
expect(contentTypePriorityPayloads[0].content_type).toBe(ContentType.UserPrefs)
expect(contentTypePriorityPayloads[1].content_type).toBe(ContentType.Component)
expect(contentTypePriorityPayloads[2].content_type).toBe(ContentType.Theme)
expect(remainingPayloads.length).toBe(4)
expect(remainingPayloads[0].uuid).toBe(prioritizedNoteUuid)
expect(remainingPayloads[1].uuid).toBe(prioritizedTagUuid)
expect(remainingPayloads[2].uuid).toBe(unprioritizedNoteUuid)
expect(remainingPayloads[3].uuid).toBe(unprioritizedTagUuid)
})
it('should sort payloads based on server updated date if same content type', () => {
const unprioritizedNoteUuid = 'unprioritized-note'
const unprioritizedTagUuid = 'unprioritized-tag'
const prioritizedNoteUuid = 'prioritized-note'
const prioritizedTagUuid = 'prioritized-tag'
payloads = [
{
content_type: ContentType.Note,
uuid: unprioritizedNoteUuid,
serverUpdatedAt: new Date(1),
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Tag,
uuid: unprioritizedTagUuid,
serverUpdatedAt: new Date(2),
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Note,
uuid: prioritizedNoteUuid,
} as FullyFormedPayloadInterface,
{
content_type: ContentType.Tag,
uuid: prioritizedTagUuid,
} as FullyFormedPayloadInterface,
]
launchPriorityUuids = [prioritizedNoteUuid, prioritizedTagUuid]
const { remainingPayloads } = GetSortedPayloadsByPriority(payloads, contentTypePriority, launchPriorityUuids)
expect(remainingPayloads.length).toBe(4)
expect(remainingPayloads[0].uuid).toBe(prioritizedNoteUuid)
expect(remainingPayloads[1].uuid).toBe(prioritizedTagUuid)
expect(remainingPayloads[2].uuid).toBe(unprioritizedTagUuid)
expect(remainingPayloads[3].uuid).toBe(unprioritizedNoteUuid)
})
})
+84 -13
View File
@@ -1,3 +1,4 @@
import { UuidString } from '@Lib/Types'
import { ContentType } from '@standardnotes/common'
import { FullyFormedPayloadInterface } from '@standardnotes/models'
@@ -6,9 +7,9 @@ import { FullyFormedPayloadInterface } from '@standardnotes/models'
* whereby the earlier a content_type appears in the priorityList,
* the earlier it will appear in the resulting sorted array.
*/
export function SortPayloadsByRecentAndContentPriority(
function SortPayloadsByRecentAndContentPriority(
payloads: FullyFormedPayloadInterface[],
priorityList: ContentType[],
contentTypePriorityList: ContentType[],
): FullyFormedPayloadInterface[] {
return payloads.sort((a, b) => {
const dateResult = new Date(b.serverUpdatedAt).getTime() - new Date(a.serverUpdatedAt).getTime()
@@ -16,18 +17,15 @@ export function SortPayloadsByRecentAndContentPriority(
let aPriority = 0
let bPriority = 0
if (priorityList) {
aPriority = priorityList.indexOf(a.content_type)
bPriority = priorityList.indexOf(b.content_type)
aPriority = contentTypePriorityList.indexOf(a.content_type)
bPriority = contentTypePriorityList.indexOf(b.content_type)
if (aPriority === -1) {
/** Not found in list, not prioritized. Set it to max value */
aPriority = priorityList.length
}
if (bPriority === -1) {
/** Not found in list, not prioritized. Set it to max value */
bPriority = priorityList.length
}
if (aPriority === -1) {
aPriority = contentTypePriorityList.length
}
if (bPriority === -1) {
bPriority = contentTypePriorityList.length
}
if (aPriority === bPriority) {
@@ -41,3 +39,76 @@ export function SortPayloadsByRecentAndContentPriority(
}
})
}
/**
* Sorts payloads according by most recently modified first, according to the priority,
* whereby the earlier a uuid appears in the priorityList,
* the earlier it will appear in the resulting sorted array.
*/
function SortPayloadsByRecentAndUuidPriority(
payloads: FullyFormedPayloadInterface[],
uuidPriorityList: UuidString[],
): FullyFormedPayloadInterface[] {
return payloads.sort((a, b) => {
const dateResult = new Date(b.serverUpdatedAt).getTime() - new Date(a.serverUpdatedAt).getTime()
let aPriority = 0
let bPriority = 0
aPriority = uuidPriorityList.indexOf(a.uuid)
bPriority = uuidPriorityList.indexOf(b.uuid)
if (aPriority === -1) {
aPriority = uuidPriorityList.length
}
if (bPriority === -1) {
bPriority = uuidPriorityList.length
}
if (aPriority === bPriority) {
return dateResult
}
if (aPriority < bPriority) {
return -1
} else {
return 1
}
})
}
export function GetSortedPayloadsByPriority(
payloads: FullyFormedPayloadInterface[],
contentTypePriorityList: ContentType[],
uuidPriorityList: UuidString[],
): {
itemsKeyPayloads: FullyFormedPayloadInterface[]
contentTypePriorityPayloads: FullyFormedPayloadInterface[]
remainingPayloads: FullyFormedPayloadInterface[]
} {
const itemsKeyPayloads: FullyFormedPayloadInterface[] = []
const contentTypePriorityPayloads: FullyFormedPayloadInterface[] = []
const remainingPayloads: FullyFormedPayloadInterface[] = []
for (let index = 0; index < payloads.length; index++) {
const payload = payloads[index]
if (payload.content_type === ContentType.ItemsKey) {
itemsKeyPayloads.push(payload)
} else if (contentTypePriorityList.includes(payload.content_type)) {
contentTypePriorityPayloads.push(payload)
} else {
remainingPayloads.push(payload)
}
}
return {
itemsKeyPayloads,
contentTypePriorityPayloads: SortPayloadsByRecentAndContentPriority(
contentTypePriorityPayloads,
contentTypePriorityList,
),
remainingPayloads: SortPayloadsByRecentAndUuidPriority(remainingPayloads, uuidPriorityList),
}
}
@@ -672,10 +672,10 @@ describe('online syncing', function () {
const payload = Factory.createStorageItemPayload(contentTypes[Math.floor(i / 2)])
originalPayloads.push(payload)
}
const sorted = SortPayloadsByRecentAndContentPriority(originalPayloads, ['C', 'A', 'B'])
expect(sorted[0].content_type).to.equal('C')
expect(sorted[2].content_type).to.equal('A')
expect(sorted[4].content_type).to.equal('B')
const { contentTypePriorityPayloads } = GetSortedPayloadsByPriority(originalPayloads, ['C', 'A', 'B'])
expect(contentTypePriorityPayloads[0].content_type).to.equal('C')
expect(contentTypePriorityPayloads[2].content_type).to.equal('A')
expect(contentTypePriorityPayloads[4].content_type).to.equal('B')
})
it('should sign in and retrieve large number of items', async function () {
+20 -20
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.146.0",
"version": "2.147.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -13,7 +13,9 @@
"e2e-server.js"
],
"license": "AGPL-3.0-or-later",
"private": true,
"publishConfig": {
"access": "public"
},
"scripts": {
"start": "webpack -w --config webpack.dev.js",
"start:test-server": "yarn node e2e-server.js",
@@ -32,6 +34,20 @@
"devDependencies": {
"@babel/core": "*",
"@babel/preset-env": "*",
"@standardnotes/api": "workspace:*",
"@standardnotes/common": "^1.43.0",
"@standardnotes/domain-events": "^2.39.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/features": "workspace:*",
"@standardnotes/files": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.2.0",
"@standardnotes/services": "workspace:*",
"@standardnotes/settings": "^1.17.0",
"@standardnotes/sncrypto-common": "workspace:*",
"@standardnotes/sncrypto-web": "workspace:*",
"@standardnotes/utils": "workspace:*",
"@types/crypto-js": "^4.1.1",
"@types/jest": "^28.1.5",
"@types/jsdom": "^16.2.14",
@@ -55,7 +71,9 @@
"lodash": "^4.17.21",
"nock": "^13.2.4",
"otplib": "^12.0.1",
"reflect-metadata": "^0.1.13",
"script-loader": "^0.7.2",
"semver": "^7.3.7",
"ts-jest": "^28.0.5",
"ts-loader": "^9.2.6",
"ts-node": "^10.8.1",
@@ -65,23 +83,5 @@
"webpack": "*",
"webpack-cli": "*",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"@standardnotes/api": "workspace:*",
"@standardnotes/common": "^1.43.0",
"@standardnotes/domain-events": "^2.39.0",
"@standardnotes/encryption": "workspace:*",
"@standardnotes/features": "workspace:*",
"@standardnotes/files": "workspace:*",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/security": "^1.2.0",
"@standardnotes/services": "workspace:*",
"@standardnotes/settings": "^1.17.0",
"@standardnotes/sncrypto-common": "workspace:*",
"@standardnotes/sncrypto-web": "workspace:*",
"@standardnotes/utils": "workspace:*",
"reflect-metadata": "^0.1.13",
"semver": "^7.3.7"
}
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.6.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/styles
## [1.6.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-01)
### Bug Fixes
+1 -2
View File
@@ -1,7 +1,6 @@
{
"name": "@standardnotes/styles",
"version": "1.6.1",
"private": true,
"version": "1.6.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"publishConfig": {
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/ui-services
# [1.13.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Features
* add sending user requests from UI ([#1927](https://github.com/standardnotes/app/issues/1927)) ([7ead0f6](https://github.com/standardnotes/app/commit/7ead0f655bb2572e5805dd26c297d520949d661a))
# [1.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* prioritize loading latest selected items ([#1930](https://github.com/standardnotes/app/issues/1930)) ([a6ef658](https://github.com/standardnotes/app/commit/a6ef658daef9a01f5ddacc967fe30d22f580799a))
## [1.11.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/ui-services
# [1.11.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.11.0",
"version": "1.13.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -0,0 +1,5 @@
import { UserRequestType } from '@standardnotes/common'
export type UserRequestParams = {
requestType: UserRequestType
}
@@ -3,4 +3,5 @@ export enum RootQueryParam {
Settings = 'settings',
DemoToken = 'demo-token',
AcceptSubscriptionInvite = 'accept-subscription-invite',
UserRequest = 'user-request',
}
@@ -1,3 +1,5 @@
import { UserRequestType } from '@standardnotes/common'
import { RouteParser } from './RouteParser'
import { RouteType } from './RouteType'
@@ -56,4 +58,12 @@ describe('route parser', () => {
expect(parser.type).toEqual(RouteType.AcceptSubscriptionInvite)
expect(parser.subscriptionInviteParams.inviteUuid).toEqual('1-2-3')
})
it('routes to user request', () => {
const url = 'https://app.standardnotes.com/?user-request=exit-discount'
const parser = new RouteParser(url)
expect(parser.type).toEqual(RouteType.UserRequest)
expect(parser.userRequestParams.requestType).toEqual(UserRequestType.ExitDiscount)
})
})
+11 -1
View File
@@ -1,10 +1,11 @@
import { Uuid } from '@standardnotes/common'
import { UserRequestType, Uuid } from '@standardnotes/common'
import { PreferenceId } from './../Preferences/PreferenceId'
import { DemoParams } from './Params/DemoParams'
import { OnboardingParams } from './Params/OnboardingParams'
import { PurchaseParams } from './Params/PurchaseParams'
import { SettingsParams } from './Params/SettingsParams'
import { SubscriptionInviteParams } from './Params/SubscriptionInviteParams'
import { UserRequestParams } from './Params/UserRequestParams'
import { RootQueryParam } from './RootQueryParam'
import { RootRoutes } from './RootRoutes'
@@ -28,6 +29,14 @@ export class RouteParser implements RouteParserInterface {
return this.parsedType
}
get userRequestParams(): UserRequestParams {
this.checkForProperRouteType(RouteType.UserRequest)
return {
requestType: this.searchParams.get(RootQueryParam.UserRequest) as UserRequestType,
}
}
get subscriptionInviteParams(): SubscriptionInviteParams {
this.checkForProperRouteType(RouteType.AcceptSubscriptionInvite)
@@ -89,6 +98,7 @@ export class RouteParser implements RouteParserInterface {
[RootQueryParam.Settings, RouteType.Settings],
[RootQueryParam.DemoToken, RouteType.Demo],
[RootQueryParam.AcceptSubscriptionInvite, RouteType.AcceptSubscriptionInvite],
[RootQueryParam.UserRequest, RouteType.UserRequest],
])
for (const rootQueryParam of rootQueryParametersMap.keys()) {
@@ -3,6 +3,7 @@ import { OnboardingParams } from './Params/OnboardingParams'
import { PurchaseParams } from './Params/PurchaseParams'
import { SettingsParams } from './Params/SettingsParams'
import { SubscriptionInviteParams } from './Params/SubscriptionInviteParams'
import { UserRequestParams } from './Params/UserRequestParams'
import { RouteType } from './RouteType'
export interface RouteParserInterface {
@@ -11,5 +12,6 @@ export interface RouteParserInterface {
get purchaseParams(): PurchaseParams
get onboardingParams(): OnboardingParams
get subscriptionInviteParams(): SubscriptionInviteParams
get userRequestParams(): UserRequestParams
get type(): RouteType
}
@@ -3,6 +3,7 @@ export enum RouteType {
Settings = 'settings',
Purchase = 'purchase',
AcceptSubscriptionInvite = 'accept-subscription-invite',
UserRequest = 'user-request',
Demo = 'demo',
None = 'none',
}
@@ -0,0 +1,17 @@
export enum PersistenceKey {
SelectedItemsController = 'selected-items-controller',
NavigationController = 'navigation-controller',
}
export type SelectionControllerPersistableValue = {
selectedUuids: string[]
}
export type NavigationControllerPersistableValue = {
selectedTagUuid: string
}
export type PersistedStateValue = {
[PersistenceKey.SelectedItemsController]: SelectionControllerPersistableValue
[PersistenceKey.NavigationController]: NavigationControllerPersistableValue
}
@@ -1,8 +1,11 @@
import { PersistedStateValue } from '../StatePersistence/StatePersistence'
export enum StorageKey {
AnonymousUserId = 'AnonymousUserId',
ShowBetaWarning = 'ShowBetaWarning',
ShowNoAccountWarning = 'ShowNoAccountWarning',
FilesNavigationEnabled = 'FilesNavigationEnabled',
MasterStatePersistenceKey = 'master-persistence-key',
}
export type StorageValue = {
@@ -10,6 +13,7 @@ export type StorageValue = {
[StorageKey.ShowBetaWarning]: boolean
[StorageKey.ShowNoAccountWarning]: boolean
[StorageKey.FilesNavigationEnabled]: boolean
[StorageKey.MasterStatePersistenceKey]: PersistedStateValue
}
export const storage = {
@@ -1,10 +1,14 @@
import { addToast, ToastType } from '@standardnotes/toast'
import { addToast, dismissToast, ToastType } from '@standardnotes/toast'
import { ToastServiceInterface } from './ToastServiceInterface'
export class ToastService implements ToastServiceInterface {
showToast(type: ToastType, message: string): void {
addToast({
hideToast(toastId: string): void {
dismissToast(toastId)
}
showToast(type: ToastType, message: string): string {
return addToast({
type: type,
message,
})
@@ -1,5 +1,6 @@
import { ToastType } from '@standardnotes/toast'
export interface ToastServiceInterface {
showToast(type: ToastType, message: string): void
showToast(type: ToastType, message: string): string
hideToast(toastId: string): void
}
+2
View File
@@ -8,6 +8,7 @@ export * from './Route/Params/OnboardingParams'
export * from './Route/Params/PurchaseParams'
export * from './Route/Params/SettingsParams'
export * from './Route/Params/SubscriptionInviteParams'
export * from './Route/Params/UserRequestParams'
export * from './Route/RootQueryParam'
export * from './Route/RouteParser'
export * from './Route/RouteParserInterface'
@@ -20,3 +21,4 @@ export * from './Storage/LocalStorage'
export * from './Theme/ThemeManager'
export * from './Toast/ToastService'
export * from './Toast/ToastServiceInterface'
export * from './StatePersistence/StatePersistence'
+60
View File
@@ -3,6 +3,66 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.93.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-04)
**Note:** Version bump only for package @standardnotes/web
## [3.93.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* padding on files view on mobile ([#1934](https://github.com/standardnotes/app/issues/1934)) ([633d618](https://github.com/standardnotes/app/commit/633d6189fbbd2a470a74f8bfd352e8b3e7af684c))
## [3.93.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* archived/trashed items getting unselected when changed ([#1932](https://github.com/standardnotes/app/issues/1932)) ([2dd0586](https://github.com/standardnotes/app/commit/2dd0586bb16cb29c7c2a538e82aca48f247910e6))
## [3.93.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* unable to add children to favorited tag; remove expand-on-click; render arrow before title ([#1931](https://github.com/standardnotes/app/issues/1931)) ([5bb4435](https://github.com/standardnotes/app/commit/5bb4435c5b10de6e0fcb580472e028f76cd2a5bd))
## [3.93.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* "No modifications allowed" error on file drag in Firefox ([de4adca](https://github.com/standardnotes/app/commit/de4adca059b169e75267c8a29012e9988a607bc2))
* files list not updating when new file is uploaded ([4036113](https://github.com/standardnotes/app/commit/40361132063e70e9851baf01eb772a0b3ff0aa1c))
## [3.93.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Bug Fixes
* correctly refresh cta banner ([305ffdf](https://github.com/standardnotes/app/commit/305ffdf9847cfe67e2d022f84c1e2443b4bc2c76))
* purchase flow close on complete ([c4dbc5c](https://github.com/standardnotes/app/commit/c4dbc5cbd2147b695403e6f57254a97d42337965))
# [3.93.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-03)
### Features
* add sending user requests from UI ([#1927](https://github.com/standardnotes/app/issues/1927)) ([7ead0f6](https://github.com/standardnotes/app/commit/7ead0f655bb2572e5805dd26c297d520949d661a))
# [3.92.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* prioritize loading latest selected items ([#1930](https://github.com/standardnotes/app/issues/1930)) ([a6ef658](https://github.com/standardnotes/app/commit/a6ef658daef9a01f5ddacc967fe30d22f580799a))
## [3.91.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Bug Fixes
* hide subscription marketing on iOS ([#1929](https://github.com/standardnotes/app/issues/1929)) ([35b21b2](https://github.com/standardnotes/app/commit/35b21b21ce2438540d799b5a2f04fe5616bf2c3e))
# [3.91.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
### Features
* dedicated files layout ([#1928](https://github.com/standardnotes/app/issues/1928)) ([dd821c9](https://github.com/standardnotes/app/commit/dd821c95e61c8cd82317ad9fb3788daff7241942))
## [3.90.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-11-02)
**Note:** Version bump only for package @standardnotes/web
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.90.11",
"version": "3.93.6",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -203,6 +203,14 @@ export class WebApplication extends SNApplication implements WebApplicationInter
return undefined
}
isNativeIOS() {
return this.isNativeMobileWeb() && this.platform === Platform.Ios
}
get hideSubscriptionMarketing() {
return this.isNativeIOS()
}
mobileDevice(): MobileDeviceInterface {
if (!this.isNativeMobileWeb()) {
throw Error('Attempting to access device as mobile device on non mobile platform')
@@ -12,7 +12,7 @@ import { NavigationController } from '@/Controllers/Navigation/NavigationControl
import { NotesController } from '@/Controllers/NotesController'
import { ElementIds } from '@/Constants/ElementIDs'
import { classNames } from '@/Utils/ConcatenateClassNames'
import { SNTag } from '@standardnotes/snjs'
import { ContentType, SNTag } from '@standardnotes/snjs'
type Props = {
application: WebApplication
@@ -95,35 +95,44 @@ const ContentList: FunctionComponent<Props> = ({
[hideTags, selectedTag, application],
)
const hasNotes = items.some((item) => item.content_type === ContentType.Note)
return (
<div
className={classNames(
'infinite-scroll overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
'md:max-h-full md:overflow-y-hidden md:hover:overflow-y-auto pointer-coarse:md:overflow-y-auto',
'md:hover:[overflow-y:_overlay]',
'flex flex-wrap pb-2 md:hover:[overflow-y:_overlay]',
hasNotes ? 'justify-center' : 'justify-center md:justify-start md:pl-1',
)}
id={ElementIds.ContentList}
onScroll={onScroll}
onKeyDown={onKeyDown}
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
>
{items.map((item) => (
<ContentListItem
key={item.uuid}
application={application}
item={item}
selected={selectedUuids.has(item.uuid)}
hideDate={hideDate}
hidePreview={hideNotePreview}
hideTags={hideTags}
hideIcon={hideEditorIcon}
sortBy={sortBy}
filesController={filesController}
onSelect={selectItem}
tags={getTagsForItem(item)}
notesController={notesController}
/>
))}
{items.map((item, index) => {
const previousItem = items[index - 1]
const nextItem = items[index + 1]
return (
<ContentListItem
key={item.uuid}
application={application}
item={item}
selected={selectedUuids.has(item.uuid)}
hideDate={hideDate}
hidePreview={hideNotePreview}
hideTags={hideTags}
hideIcon={hideEditorIcon}
sortBy={sortBy}
filesController={filesController}
onSelect={selectItem}
tags={getTagsForItem(item)}
notesController={notesController}
isPreviousItemTiled={previousItem?.content_type === ContentType.File}
isNextItemTiled={nextItem?.content_type === ContentType.File}
/>
)
})}
</div>
)
}
@@ -1,15 +1,16 @@
import { ContentType } from '@standardnotes/snjs'
import { ContentType, FileItem, SNNote } from '@standardnotes/snjs'
import React, { FunctionComponent } from 'react'
import FileListItem from './FileListItem'
import NoteListItem from './NoteListItem'
import { AbstractListItemProps, doListItemPropsMeritRerender } from './Types/AbstractListItemProps'
import { ListableContentItem } from './Types/ListableContentItem'
const ContentListItem: FunctionComponent<AbstractListItemProps> = (props) => {
const ContentListItem: FunctionComponent<AbstractListItemProps<ListableContentItem>> = (props) => {
switch (props.item.content_type) {
case ContentType.Note:
return <NoteListItem {...props} />
return <NoteListItem {...props} item={props.item as SNNote} />
case ContentType.File:
return <FileListItem {...props} />
return <FileListItem {...props} item={props.item as FileItem} />
default:
return null
}
@@ -1,7 +1,7 @@
import { KeyboardKey, KeyboardModifier } from '@standardnotes/ui-services'
import { WebApplication } from '@/Application/Application'
import { PANEL_NAME_NOTES } from '@/Constants/Constants'
import { FileItem, PrefKey, SystemViewId } from '@standardnotes/snjs'
import { FileItem, PrefKey } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react'
import ContentList from '@/Components/ContentListView/ContentList'
@@ -110,6 +110,7 @@ const ContentListView: FunctionComponent<Props> = ({
renderedItems,
items,
searchBarElement,
isCurrentNoteTemplate,
} = itemListController
const { selectedUuids, selectNextItem, selectPreviousItem } = selectionController
@@ -118,10 +119,7 @@ const ContentListView: FunctionComponent<Props> = ({
const icon = selectedTag?.iconString
const isFilesSmartView = useMemo(
() => navigationController.selected?.uuid === SystemViewId.Files,
[navigationController.selected?.uuid],
)
const isFilesSmartView = useMemo(() => navigationController.isInFilesView, [navigationController.isInFilesView])
const addNewItem = useCallback(async () => {
if (isFilesSmartView) {
@@ -215,10 +213,14 @@ const ContentListView: FunctionComponent<Props> = ({
const panelResizeFinishCallback: ResizeFinishCallback = useCallback(
(width, _lastLeft, _isMaxWidth, isCollapsed) => {
application.setPreference(PrefKey.NotesPanelWidth, width).catch(console.error)
if (selectedAsTag) {
navigationController.setPanelWidthForTag(selectedAsTag, width)
} else {
application.setPreference(PrefKey.NotesPanelWidth, width).catch(console.error)
}
application.publishPanelDidResizeEvent(PANEL_NAME_NOTES, isCollapsed)
},
[application],
[application, selectedAsTag, navigationController],
)
const addButtonLabel = useMemo(
@@ -243,15 +245,26 @@ const ContentListView: FunctionComponent<Props> = ({
[selectionController],
)
useEffect(() => {
const hasEditorPane = selectedUuids.size > 0 || renderedItems.length === 0 || isCurrentNoteTemplate
if (!hasEditorPane) {
itemsViewPanelRef.current?.style.removeProperty('width')
}
}, [selectedUuids, itemsViewPanelRef, isCurrentNoteTemplate, renderedItems])
const hasEditorPane = selectedUuids.size > 0 || renderedItems.length === 0 || isCurrentNoteTemplate
return (
<div
id="items-column"
className={classNames(
'sn-component section app-column flex h-full flex-col overflow-hidden pt-safe-top',
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full',
isTabletScreenSize && !isNotesListVisibleOnTablets
? 'pointer-coarse:md-only:!w-0 pointer-coarse:lg-only:!w-0'
: 'pointer-coarse:md-only:!w-60 pointer-coarse:lg-only:!w-60',
hasEditorPane ? 'xl:w-[24rem] xsm-only:!w-full sm-only:!w-full' : 'w-full md:min-w-[400px]',
hasEditorPane
? isTabletScreenSize && !isNotesListVisibleOnTablets
? 'pointer-coarse:md-only:!w-0 pointer-coarse:lg-only:!w-0'
: 'pointer-coarse:md-only:!w-60 pointer-coarse:lg-only:!w-60'
: '',
)}
aria-label={'Notes & Files'}
ref={itemsViewPanelRef}
@@ -327,7 +340,7 @@ const ContentListView: FunctionComponent<Props> = ({
) : null}
<div className="absolute bottom-0 h-safe-bottom w-full" />
</ResponsivePaneContent>
{itemsViewPanelRef.current && (
{hasEditorPane && itemsViewPanelRef.current && (
<PanelResizer
collapsable={true}
hoverable={true}
@@ -1,5 +1,5 @@
import { formatDateAndTimeForNote } from '@/Utils/DateUtils'
import { SNTag } from '@standardnotes/snjs'
import { isNote, SNTag } from '@standardnotes/snjs'
import { ComponentPropsWithoutRef, forwardRef, FunctionComponent, Ref } from 'react'
import ListItemFlagIcons from '../ListItemFlagIcons'
import ListItemMetadata from '../ListItemMetadata'
@@ -65,7 +65,7 @@ export const DailyItemCell = forwardRef(
{item && (
<>
<ListItemTitle item={item} />
<ListItemNotePreviewText hidePreview={hidePreview} item={item} lineLimit={5} />
{isNote(item) && <ListItemNotePreviewText hidePreview={hidePreview} item={item} lineLimit={5} />}
<ListItemMetadata item={item} hideDate={hideDate} sortBy={'created_at'} />
<ListItemTags hideTags={hideTags} tags={tags} />
</>
@@ -3,15 +3,16 @@ import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useRef } from 'react'
import { getFileIconComponent } from '../FilePreview/getFileIconComponent'
import ListItemConflictIndicator from './ListItemConflictIndicator'
import ListItemFlagIcons from './ListItemFlagIcons'
import ListItemTags from './ListItemTags'
import ListItemMetadata from './ListItemMetadata'
import { DisplayableListItemProps } from './Types/DisplayableListItemProps'
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
import { useContextMenuEvent } from '@/Hooks/useContextMenuEvent'
import { classNames } from '@/Utils/ConcatenateClassNames'
import { formatSizeToReadableString } from '@standardnotes/filepicker'
const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
const FileListItem: FunctionComponent<DisplayableListItemProps<FileItem>> = ({
application,
filesController,
hideDate,
@@ -67,7 +68,7 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
const IconComponent = () =>
getFileIconComponent(
application.iconsController.getIconForFileType((item as FileItem).mimeType),
'w-5 h-5 flex-shrink-0',
'w-10 h-10 flex-shrink-0',
)
useContextMenuEvent(listItemRef, openContextMenu)
@@ -75,28 +76,41 @@ const FileListItem: FunctionComponent<DisplayableListItemProps> = ({
return (
<div
ref={listItemRef}
className={`content-list-item flex w-full cursor-pointer items-stretch text-text ${
selected && 'selected border-l-2px border-solid border-info'
}`}
className={classNames('flex max-h-[300px] w-[190px] cursor-pointer px-1 pt-2 text-text md:w-[200px]')}
id={item.uuid}
onClick={onClick}
>
{!hideIcon ? (
<div className="mr-0 flex flex-col items-center justify-between p-4.5 pr-3">
<IconComponent />
<div
className={`flex flex-col justify-between overflow-hidden rounded bg-passive-5 pt-5 transition-all hover:bg-passive-4 ${
selected ? 'border-[1px] border-solid border-info' : 'border-[1px] border-solid border-border'
}`}
>
<div className={'px-5'}>
{!hideIcon ? (
<div className="mr-0">
<IconComponent />
</div>
) : (
<div className="pr-4" />
)}
<div className="min-w-0 flex-grow py-4 px-0">
<div className="line-clamp-2 overflow-hidden text-editor font-semibold">
<div className="break-word line-clamp-2 mr-2 overflow-hidden">{item.title}</div>
</div>
<ListItemMetadata item={item} hideDate={hideDate} sortBy={sortBy} />
<ListItemTags hideTags={hideTags} tags={tags} />
<ListItemConflictIndicator item={item} />
</div>
</div>
) : (
<div className="pr-4" />
)}
<div className="min-w-0 flex-grow border-b border-solid border-border py-4 px-0">
<div className="flex items-start justify-between overflow-hidden text-base font-semibold leading-[1.3]">
<div className="break-word mr-2">{item.title}</div>
<div
className={classNames(
'border-t-[1px] border-solid border-border p-3 text-xs font-bold',
selected ? 'bg-info text-info-contrast' : 'bg-passive-4 text-neutral',
)}
>
{formatSizeToReadableString(item.decryptedSize)}
</div>
<ListItemMetadata item={item} hideDate={hideDate} sortBy={sortBy} />
<ListItemTags hideTags={hideTags} tags={tags} />
<ListItemConflictIndicator item={item} />
</div>
<ListItemFlagIcons item={item} />
</div>
)
}
@@ -118,7 +118,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
void changePreferences({ sortBy: sort })
}
},
[preferences, changePreferences, toggleSortReverse],
[preferences.sortBy, toggleSortReverse, changePreferences],
)
const toggleSortByDateModified = useCallback(() => {
@@ -212,14 +212,17 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
{!DailyEntryModeEnabled &&
'Create powerful workflows and organizational layouts with per-tag display preferences.'}
</p>
<Button
primary
small
className="col-start-1 col-end-3 mt-3 justify-self-start uppercase"
onClick={() => application.openPurchaseFlow()}
>
Upgrade Features
</Button>
{!application.hideSubscriptionMarketing && (
<Button
primary
small
className="col-start-1 col-end-3 mt-3 justify-self-start uppercase"
onClick={() => application.openPurchaseFlow()}
>
Upgrade Features
</Button>
)}
</div>
)
@@ -11,11 +11,13 @@ type Props = {
starred: ListableContentItem['starred']
}
hasFiles?: boolean
hasBorder?: boolean
className?: string
}
const ListItemFlagIcons: FunctionComponent<Props> = ({ item, hasFiles = false }) => {
const ListItemFlagIcons: FunctionComponent<Props> = ({ item, hasFiles = false, hasBorder = true, className }) => {
return (
<div className="flex items-start border-b border-solid border-border p-4 pl-0">
<div className={`flex items-start ${hasBorder && 'border-b border-solid border-border'} ${className} pl-0`}>
{item.locked && (
<span className="flex items-center" title="Editing Disabled">
<Icon ariaLabel="Editing Disabled" type="pencil-off" className="text-info" size="medium" />
@@ -1,9 +1,8 @@
import { sanitizeHtmlString } from '@standardnotes/snjs'
import { sanitizeHtmlString, SNNote } from '@standardnotes/snjs'
import { FunctionComponent } from 'react'
import { ListableContentItem } from './Types/ListableContentItem'
type Props = {
item: ListableContentItem
item: SNNote
hidePreview: boolean
lineLimit?: number
}
@@ -1,10 +1,11 @@
import { FunctionComponent } from 'react'
import Icon from '@/Components/Icon/Icon'
import { DisplayableListItemProps } from './Types/DisplayableListItemProps'
import { ListableContentItem } from './Types/ListableContentItem'
type Props = {
hideTags: boolean
tags: DisplayableListItemProps['tags']
tags: DisplayableListItemProps<ListableContentItem>['tags']
}
const ListItemTags: FunctionComponent<Props> = ({ hideTags, tags }) => {
@@ -14,8 +14,9 @@ import { useContextMenuEvent } from '@/Hooks/useContextMenuEvent'
import ListItemNotePreviewText from './ListItemNotePreviewText'
import { ListItemTitle } from './ListItemTitle'
import { log, LoggingDomain } from '@/Logging'
import { classNames } from '@/Utils/ConcatenateClassNames'
const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
const NoteListItem: FunctionComponent<DisplayableListItemProps<SNNote>> = ({
application,
notesController,
onSelect,
@@ -27,6 +28,8 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
selected,
sortBy,
tags,
isPreviousItemTiled,
isNextItemTiled,
}) => {
const { toggleAppPane } = useResponsiveAppPane()
@@ -73,12 +76,17 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
log(LoggingDomain.ItemsList, 'Rendering note list item', item.title)
const hasOffsetBorder = !isNextItemTiled
return (
<div
ref={listItemRef}
className={`content-list-item flex w-full cursor-pointer items-stretch text-text ${
selected && `selected border-l-2 border-solid border-accessory-tint-${tint}`
}`}
className={classNames(
'content-list-item text-tex flex w-full cursor-pointer items-stretch',
selected && `selected border-l-2 border-solid border-accessory-tint-${tint}`,
isPreviousItemTiled && 'mt-3 border-t border-solid border-t-border',
isNextItemTiled && 'mb-3 border-b border-solid border-b-border',
)}
id={item.uuid}
onClick={onClick}
>
@@ -89,14 +97,14 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps> = ({
) : (
<div className="pr-4" />
)}
<div className="min-w-0 flex-grow border-b border-solid border-border py-4 px-0">
<div className={`min-w-0 flex-grow ${hasOffsetBorder && 'border-b border-solid border-border'} py-4 px-0`}>
<ListItemTitle item={item} />
<ListItemNotePreviewText item={item} hidePreview={hidePreview} />
<ListItemMetadata item={item} hideDate={hideDate} sortBy={sortBy} />
<ListItemTags hideTags={hideTags} tags={tags} />
<ListItemConflictIndicator item={item} />
</div>
<ListItemFlagIcons item={item} hasFiles={hasFiles} />
<ListItemFlagIcons className="p-4" item={item} hasFiles={hasFiles} hasBorder={hasOffsetBorder} />
</div>
)
}
@@ -4,7 +4,9 @@ import { NotesController } from '@/Controllers/NotesController'
import { SortableItem, SNTag, Uuids } from '@standardnotes/snjs'
import { ListableContentItem } from './ListableContentItem'
export type AbstractListItemProps = {
type KeysOfUnion<T> = T extends T ? keyof T : never
export type AbstractListItemProps<I extends ListableContentItem> = {
application: WebApplication
filesController: FilesController
notesController: NotesController
@@ -13,14 +15,19 @@ export type AbstractListItemProps = {
hideIcon: boolean
hideTags: boolean
hidePreview: boolean
item: ListableContentItem
item: I
selected: boolean
sortBy: keyof SortableItem | undefined
tags: SNTag[]
isPreviousItemTiled?: boolean
isNextItemTiled?: boolean
}
export function doListItemPropsMeritRerender(previous: AbstractListItemProps, next: AbstractListItemProps): boolean {
const simpleComparison: (keyof AbstractListItemProps)[] = [
export function doListItemPropsMeritRerender(
previous: AbstractListItemProps<ListableContentItem>,
next: AbstractListItemProps<ListableContentItem>,
): boolean {
const simpleComparison: (keyof AbstractListItemProps<ListableContentItem>)[] = [
'onSelect',
'hideDate',
'hideIcon',
@@ -28,6 +35,8 @@ export function doListItemPropsMeritRerender(previous: AbstractListItemProps, ne
'hidePreview',
'selected',
'sortBy',
'isPreviousItemTiled',
'isNextItemTiled',
]
for (const key of simpleComparison) {
@@ -83,7 +92,7 @@ function doesItemChangeMeritRerender(previous: ListableContentItem, next: Listab
return true
}
const propertiesMeritingRerender: (keyof ListableContentItem)[] = [
const propertiesMeritingRerender: KeysOfUnion<ListableContentItem>[] = [
'title',
'protected',
'updatedAtString',
@@ -97,7 +106,7 @@ function doesItemChangeMeritRerender(previous: ListableContentItem, next: Listab
]
for (const key of propertiesMeritingRerender) {
if (previous[key] !== next[key]) {
if (previous[key as keyof ListableContentItem] !== next[key as keyof ListableContentItem]) {
return true
}
}
@@ -1,7 +1,8 @@
import { SNTag } from '@standardnotes/snjs'
import { AbstractListItemProps } from './AbstractListItemProps'
import { ListableContentItem } from './ListableContentItem'
export type DisplayableListItemProps = AbstractListItemProps & {
export type DisplayableListItemProps<I extends ListableContentItem> = AbstractListItemProps<I> & {
tags: {
uuid: SNTag['uuid']
title: SNTag['title']
@@ -1,12 +1,3 @@
import { DecryptedItem, ItemContent } from '@standardnotes/snjs'
import { FileItem, SNNote } from '@standardnotes/snjs'
export type ListableContentItem = DecryptedItem<ItemContent> & {
title: string
protected: boolean
updatedAtString?: string
createdAtString?: string
hidePreview?: boolean
preview_html?: string
preview_plain?: string
text?: string
}
export type ListableContentItem = SNNote | FileItem
@@ -100,6 +100,20 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
[application],
)
const handleDragStart = useCallback(
(event: DragEvent) => {
if (isHandlingFileDrag(event, application)) {
event.preventDefault()
event.stopPropagation()
if (event.dataTransfer) {
event.dataTransfer.clearData()
}
}
},
[application],
)
const handleDragIn = useCallback(
(event: DragEvent) => {
if (!isHandlingFileDrag(event, application)) {
@@ -200,7 +214,6 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
}
})
event.dataTransfer.clearData()
dragCounter.current = 0
}
},
@@ -208,18 +221,20 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
)
useEffect(() => {
window.addEventListener('dragstart', handleDragStart)
window.addEventListener('dragenter', handleDragIn)
window.addEventListener('dragleave', handleDragOut)
window.addEventListener('dragover', handleDrag)
window.addEventListener('drop', handleDrop)
return () => {
window.removeEventListener('dragstart', handleDragStart)
window.removeEventListener('dragenter', handleDragIn)
window.removeEventListener('dragleave', handleDragOut)
window.removeEventListener('dragover', handleDrag)
window.removeEventListener('drop', handleDrop)
}
}, [handleDragIn, handleDrop, handleDrag, handleDragOut])
}, [handleDragIn, handleDrop, handleDrag, handleDragOut, handleDragStart])
const contextValue = useMemo(() => {
return {
@@ -386,6 +386,7 @@ class Footer extends AbstractComponent<Props, State> {
<UpgradeNow
application={this.application}
featuresController={this.viewControllerManager.featuresController}
subscriptionContoller={this.viewControllerManager.subscriptionController}
/>
{this.state.showBetaWarning && (
<Fragment>
@@ -1,16 +1,22 @@
import { WebApplication } from '@/Application/Application'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { SubscriptionController } from '@/Controllers/Subscription/SubscriptionController'
import { observer } from 'mobx-react-lite'
import { loadPurchaseFlowUrl } from '../PurchaseFlow/PurchaseFlowFunctions'
type Props = {
application: WebApplication
featuresController: FeaturesController
subscriptionContoller: SubscriptionController
}
const UpgradeNow = ({ application, featuresController }: Props) => {
const UpgradeNow = ({ application, featuresController, subscriptionContoller }: Props) => {
const shouldShowCTA = !featuresController.hasFolders
const hasAccount = application.hasAccount()
const hasAccount = subscriptionContoller.hasAccount
if (hasAccount && subscriptionContoller.hideSubscriptionMarketing) {
return null
}
return shouldShowCTA ? (
<div className="flex h-full items-center px-2">
@@ -286,11 +286,13 @@ const NotesOptions = ({
const switchClassNames = classNames(textClassNames, defaultClassNames, 'justify-between')
const firstItemClass = 'pt-4'
return (
<>
{notes.length === 1 && (
<>
<button className={defaultClassNames} onClick={openRevisionHistoryModal}>
<button className={classNames(defaultClassNames, firstItemClass)} onClick={openRevisionHistoryModal}>
<Icon type="history" className={iconClass} />
Note history
</button>
@@ -31,12 +31,14 @@ const NoSubscription: FunctionComponent<Props> = ({ application }) => {
<Text>You don't have a Standard Notes subscription yet.</Text>
{isLoadingPurchaseFlow && <Text>Redirecting you to the subscription page...</Text>}
{purchaseFlowError && <Text className="text-danger">{purchaseFlowError}</Text>}
<div className="flex">
<LinkButton className="mt-3 mr-3 min-w-20" label="Learn More" link={window.plansUrl as string} />
{application.hasAccount() && (
<Button className="mt-3 min-w-20" primary label="Subscribe" onClick={onPurchaseClick} />
)}
</div>
{!application.hideSubscriptionMarketing && (
<div className="flex">
<LinkButton className="mt-3 mr-3 min-w-20" label="Learn More" link={window.plansUrl as string} />
{application.hasAccount() && (
<Button className="mt-3 min-w-20" primary label="Subscribe" onClick={onPurchaseClick} />
)}
</div>
)}
</>
)
}
@@ -34,12 +34,15 @@ const NoProSubscription: FunctionComponent<Props> = ({ application }) => {
</Text>
{isLoadingPurchaseFlow && <Text>Redirecting you to the subscription page...</Text>}
{purchaseFlowError && <Text className="text-danger">{purchaseFlowError}</Text>}
<div className="flex">
<LinkButton className="mt-3 mr-3 min-w-20" label="Learn More" link={window.plansUrl as string} />
{application.hasAccount() && (
<Button className="mt-3 min-w-20" primary label="Upgrade" onClick={onPurchaseClick} />
)}
</div>
{!application.hideSubscriptionMarketing && (
<div className="flex">
<LinkButton className="mt-3 mr-3 min-w-20" label="Learn More" link={window.plansUrl as string} />
{application.hasAccount() && (
<Button className="mt-3 min-w-20" primary label="Upgrade" onClick={onPurchaseClick} />
)}
</div>
)}
</>
)
}
@@ -17,6 +17,12 @@ const Persistence = ({ application }: Props) => {
const toggleStatePersistence = (shouldPersist: boolean) => {
application.setValue(ShouldPersistNoteStateKey, shouldPersist)
setShouldPersistNoteState(shouldPersist)
if (shouldPersist) {
application.getViewControllerManager().persistValues()
} else {
application.getViewControllerManager().clearPersistedValues()
}
}
return (
@@ -61,15 +61,17 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
To take advantage of <span className="font-semibold">{featureName}</span> and other advanced features,
upgrade your current plan.
</AlertDialogDescription>
<div className="p-4">
<button
onClick={handleClick}
className="no-border w-full cursor-pointer rounded bg-info py-2 font-bold text-info-contrast hover:brightness-125 focus:brightness-125"
ref={plansButtonRef}
>
Upgrade
</button>
</div>
{!application.hideSubscriptionMarketing && (
<div className="p-4">
<button
onClick={handleClick}
className="no-border w-full cursor-pointer rounded bg-info py-2 font-bold text-info-contrast hover:brightness-125 focus:brightness-125"
ref={plansButtonRef}
>
Upgrade
</button>
</div>
)}
</div>
</div>
</AlertDialog>
@@ -91,10 +91,15 @@ const CreateAccount: FunctionComponent<Props> = ({ viewControllerManager, applic
try {
await application.register(email, password)
loadPurchaseFlowUrl(application).catch((err) => {
console.error(err)
application.alertService.alert(err).catch(console.error)
})
viewControllerManager.purchaseFlowController.closePurchaseFlow()
if (!application.hideSubscriptionMarketing) {
loadPurchaseFlowUrl(application).catch((err) => {
console.error(err)
application.alertService.alert(err).catch(console.error)
})
}
} catch (err) {
console.error(err)
application.alertService.alert(err as string).catch(console.error)
@@ -74,10 +74,14 @@ const SignIn: FunctionComponent<Props> = ({ viewControllerManager, application }
if (response.error || response.data?.error) {
throw new Error(response.error?.message || response.data?.error?.message)
} else {
loadPurchaseFlowUrl(application).catch((err) => {
console.error(err)
application.alertService.alert(err).catch(console.error)
})
viewControllerManager.purchaseFlowController.closePurchaseFlow()
if (!application.hideSubscriptionMarketing) {
loadPurchaseFlowUrl(application).catch((err) => {
console.error(err)
application.alertService.alert(err).catch(console.error)
})
}
}
} catch (err) {
console.error(err)
@@ -2,6 +2,7 @@ import { WebApplication } from '@/Application/Application'
import { FunctionComponent, MouseEventHandler, useCallback } from 'react'
import Switch from '@/Components/Switch/Switch'
import { isMobileScreen } from '@/Utils'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
application: WebApplication
@@ -29,7 +30,11 @@ const FocusModeSwitch: FunctionComponent<Props> = ({ application, onToggle, onCl
return (
<button
className="group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2"
className={classNames(
'group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left',
'text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2',
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
)}
onClick={toggle}
>
<div className="flex items-center">Focused Writing</div>
@@ -53,7 +53,7 @@ const PanelSettingsSection = ({ application }: Props) => {
}, [application])
return (
<div className="hidden text-sm md:block pointer-coarse:md-only:hidden pointer-coarse:lg-only:hidden">
<div className="hidden md:block pointer-coarse:md-only:hidden pointer-coarse:lg-only:hidden">
<MenuItem
type={MenuItemType.SwitchButton}
className="py-1 hover:bg-contrast focus:bg-info-backdrop"
@@ -21,6 +21,7 @@ import HorizontalSeparator from '../Shared/HorizontalSeparator'
import { QuickSettingsController } from '@/Controllers/QuickSettingsController'
import PanelSettingsSection from './PanelSettingsSection'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import { classNames } from '@/Utils/ConcatenateClassNames'
const focusModeAnimationDuration = 1255
@@ -173,7 +174,11 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
<div className="my-1 px-3 text-sm font-semibold uppercase text-text">Tools</div>
{toggleableComponents.map((component) => (
<button
className="flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
className={classNames(
'flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left',
'text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none',
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
)}
onClick={() => {
toggleComponent(component)
}}
@@ -191,7 +196,11 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
)}
<div className="my-1 px-3 text-sm font-semibold uppercase text-text">Appearance</div>
<button
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
className={classNames(
'flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left',
'text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none',
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
)}
onClick={toggleDefaultTheme}
ref={defaultThemeButtonRef}
>
@@ -8,6 +8,7 @@ import { ThemeItem } from './ThemeItem'
import RadioIndicator from '../Radio/RadioIndicator'
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
import { isMobileScreen } from '@/Utils'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
item: ThemeItem
@@ -54,9 +55,11 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ application, item }) => {
return (
<button
className={
'group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2 md:text-sm'
}
className={classNames(
'group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5',
'text-left text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2',
'text-mobile-menu-item md:text-tablet-menu-item lg:text-menu-item',
)}
onClick={toggleTheme}
>
{item.component?.isLayerable() ? (
@@ -72,11 +72,11 @@ const ResponsivePaneProvider = ({ paneController, children }: ProviderProps) =>
useEffect(() => {
if (previousSelectedPane) {
const previousPaneElement = document.getElementById(ElementIds[previousSelectedPane])
previousPaneElement?.classList.remove('selected')
previousPaneElement?.removeAttribute('data-selected-pane')
}
const currentPaneElement = document.getElementById(ElementIds[currentSelectedPane])
currentPaneElement?.classList.add('selected')
currentPaneElement?.setAttribute('data-selected-pane', '')
}, [currentSelectedPane, previousSelectedPane])
const addAndroidBackHandler = useAndroidBackHandler()
@@ -69,7 +69,11 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
label="Go to items list"
icon="chevron-left"
/>
<UpgradeNow application={application} featuresController={viewControllerManager.featuresController} />
<UpgradeNow
application={application}
subscriptionContoller={viewControllerManager.subscriptionController}
featuresController={viewControllerManager.featuresController}
/>
<RoundIconButton
className="ml-2.5 bg-default"
onClick={() => {
@@ -50,7 +50,7 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState }) => {
}, [setTitle, view])
const selectCurrentTag = useCallback(async () => {
await tagsState.setSelectedTag(view, {
await tagsState.setSelectedTag(view, 'views', {
userTriggered: true,
})
toggleAppPane(AppPaneId.Items)
@@ -86,7 +86,7 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState }) => {
}, [inputRef, isEditing])
const onClickRename = useCallback(() => {
tagsState.editingTag = view
tagsState.setEditingTag(view)
}, [tagsState, view])
const onClickSave = useCallback(() => {
@@ -40,8 +40,7 @@ const TagContextMenu = ({ navigationController, isEntitledToFolders, selectedTag
const onClickRename = useCallback(() => {
navigationController.setContextMenuOpen(false)
navigationController.editingFrom = navigationController.contextMenuOpenFrom
navigationController.editingTag = selectedTag
navigationController.setEditingTag(selectedTag)
}, [navigationController, selectedTag])
const onClickDelete = useCallback(() => {
@@ -1 +1 @@
export type TagListSectionType = 'all' | 'favorites'
export type TagListSectionType = 'views' | 'all' | 'favorites'

Some files were not shown because too many files have changed in this diff Show More