mirror of
https://github.com/standardnotes/app
synced 2026-09-20 21:13:51 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e54e442399 | ||
|
|
a6029e3ef1 | ||
|
|
f2c92d24f3 | ||
|
|
8be872feee | ||
|
|
24f878ecef | ||
|
|
ca0a7fa8a7 | ||
|
|
d79484739b | ||
|
|
6559c66ecf | ||
|
|
b43f306d6b | ||
|
|
18fdc482a9 | ||
|
|
f26ad410e2 | ||
|
|
ca9895cac1 | ||
|
|
18b7728145 | ||
|
|
21b34a5039 | ||
|
|
a683ca4b40 | ||
|
|
94361f0222 | ||
|
|
24afeaed63 | ||
|
|
cddc5e101b | ||
|
|
6a84f25301 | ||
|
|
a3d1f7d663 | ||
|
|
3b1d63ee71 | ||
|
|
317167adea | ||
|
|
77f72ff7b6 | ||
|
|
d508425b34 | ||
|
|
d920ed52ad | ||
|
|
5503e672be | ||
|
|
779d935dba | ||
|
|
2936ef174c | ||
|
|
600b690249 | ||
|
|
4246c5181a | ||
|
|
2ba427602d | ||
|
|
b8cbd446b8 | ||
|
|
f95a942f6e | ||
|
|
4865e3ba28 | ||
|
|
e1c5d52dbe | ||
|
|
cd0111d6b1 | ||
|
|
40a22a1403 | ||
|
|
2775d5e161 | ||
|
|
ea8f9dba03 | ||
|
|
86bc242ba2 | ||
|
|
5af0ff8f2e |
BIN
Binary file not shown.
@@ -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.26.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.26.48",
|
||||
"version": "1.26.49",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface HttpRequestOptions {
|
||||
authentication?: string
|
||||
headers?: Record<string, string>[]
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { Paths } from '../Server/Auth/Paths'
|
||||
import { SessionRefreshResponseBody } from '../Response/Auth/SessionRefreshResponseBody'
|
||||
import { FetchRequestHandler } from './FetchRequestHandler'
|
||||
import { RequestHandlerInterface } from './RequestHandlerInterface'
|
||||
import { HttpRequestOptions } from './HttpRequestOptions'
|
||||
|
||||
export class HttpService implements HttpServiceInterface {
|
||||
private session?: Session | LegacySession
|
||||
@@ -76,7 +77,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
async get<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
|
||||
async get<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>> {
|
||||
if (!this.host) {
|
||||
throw new Error('Attempting to make network request before host is set')
|
||||
}
|
||||
@@ -85,7 +86,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Get,
|
||||
authentication: authentication ?? this.getSessionAccessToken(),
|
||||
authentication: options?.authentication ?? this.getSessionAccessToken(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ export class HttpService implements HttpServiceInterface {
|
||||
})
|
||||
}
|
||||
|
||||
async post<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
|
||||
async post<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>> {
|
||||
if (!this.host) {
|
||||
throw new Error('Attempting to make network request before host is set')
|
||||
}
|
||||
@@ -107,34 +108,35 @@ export class HttpService implements HttpServiceInterface {
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Post,
|
||||
authentication: authentication ?? this.getSessionAccessToken(),
|
||||
authentication: options?.authentication ?? this.getSessionAccessToken(),
|
||||
customHeaders: options?.headers,
|
||||
})
|
||||
}
|
||||
|
||||
async put<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
|
||||
async put<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>> {
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Put,
|
||||
authentication: authentication ?? this.getSessionAccessToken(),
|
||||
authentication: options?.authentication ?? this.getSessionAccessToken(),
|
||||
})
|
||||
}
|
||||
|
||||
async patch<T>(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
|
||||
async patch<T>(path: string, params: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>> {
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Patch,
|
||||
authentication: authentication ?? this.getSessionAccessToken(),
|
||||
authentication: options?.authentication ?? this.getSessionAccessToken(),
|
||||
})
|
||||
}
|
||||
|
||||
async delete<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>> {
|
||||
async delete<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>> {
|
||||
return this.runHttp({
|
||||
url: joinPaths(this.host, path),
|
||||
params,
|
||||
verb: HttpVerb.Delete,
|
||||
authentication: authentication ?? this.getSessionAccessToken(),
|
||||
authentication: options?.authentication ?? this.getSessionAccessToken(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { LegacySession, Session } from '@standardnotes/domain-core'
|
||||
import { HttpRequest, HttpRequestParams, HttpResponse, HttpResponseMeta } from '@standardnotes/responses'
|
||||
|
||||
import { HttpRequestOptions } from './HttpRequestOptions'
|
||||
|
||||
export interface HttpServiceInterface {
|
||||
setHost(host: string): void
|
||||
getHost(): string
|
||||
|
||||
get<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
|
||||
get<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>>
|
||||
getExternal<T>(url: string, params?: HttpRequestParams): Promise<HttpResponse<T>>
|
||||
post<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
|
||||
put<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
|
||||
patch<T>(path: string, params: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
|
||||
delete<T>(path: string, params?: HttpRequestParams, authentication?: string): Promise<HttpResponse<T>>
|
||||
post<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>>
|
||||
put<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>>
|
||||
patch<T>(path: string, params: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>>
|
||||
delete<T>(path: string, params?: HttpRequestParams, options?: HttpRequestOptions): Promise<HttpResponse<T>>
|
||||
runHttp<T>(httpRequest: HttpRequest): Promise<HttpResponse<T>>
|
||||
|
||||
setSession(session: Session | LegacySession): void
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './HttpService'
|
||||
export * from './FetchRequestHandler'
|
||||
export * from './HttpRequestOptions'
|
||||
export * from './HttpServiceInterface'
|
||||
export * from './XMLHttpRequestState'
|
||||
|
||||
@@ -8,4 +8,5 @@ export type CreateSharedVaultValetTokenParams = {
|
||||
unencryptedFileSize?: number
|
||||
moveOperationType?: SharedVaultMoveType
|
||||
sharedVaultToSharedVaultMoveTargetUuid?: string
|
||||
sharedVaultOwnerUuid?: string
|
||||
}
|
||||
|
||||
@@ -25,13 +25,23 @@ export class SharedVaultServer implements SharedVaultServerInterface {
|
||||
createSharedVaultFileValetToken(
|
||||
params: CreateSharedVaultValetTokenParams,
|
||||
): Promise<HttpResponse<CreateSharedVaultValetTokenResponse>> {
|
||||
return this.httpService.post(SharedVaultsPaths.createSharedVaultFileValetToken(params.sharedVaultUuid), {
|
||||
file_uuid: params.fileUuid,
|
||||
remote_identifier: params.remoteIdentifier,
|
||||
operation: params.operation,
|
||||
unencrypted_file_size: params.unencryptedFileSize,
|
||||
move_operation_type: params.moveOperationType,
|
||||
shared_vault_to_shared_vault_move_target_uuid: params.sharedVaultToSharedVaultMoveTargetUuid,
|
||||
})
|
||||
let headers = undefined
|
||||
if (params.sharedVaultOwnerUuid) {
|
||||
headers = [{ 'x-shared-vault-owner-context': params.sharedVaultOwnerUuid }]
|
||||
}
|
||||
return this.httpService.post(
|
||||
SharedVaultsPaths.createSharedVaultFileValetToken(params.sharedVaultUuid),
|
||||
{
|
||||
file_uuid: params.fileUuid,
|
||||
remote_identifier: params.remoteIdentifier,
|
||||
operation: params.operation,
|
||||
unencrypted_file_size: params.unencryptedFileSize,
|
||||
move_operation_type: params.moveOperationType,
|
||||
shared_vault_to_shared_vault_move_target_uuid: params.sharedVaultToSharedVaultMoveTargetUuid,
|
||||
},
|
||||
{
|
||||
headers,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [1.1.186](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.185](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.184](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.183](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.182](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.181](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.180](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.179](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.178](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.177](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.176](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.175](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.174](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.173](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.172](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.171](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/clipper",
|
||||
"description": "Web clipper browser extension for Standard Notes",
|
||||
"version": "1.1.171",
|
||||
"version": "1.1.186",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
|
||||
|
||||
@@ -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.108.118](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.116](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.115](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.114](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.113](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.112](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.111](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.110](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.109](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.108](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.107](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.106](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.105](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.104](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.103](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -128,7 +128,7 @@ async function configureWindow(remoteBridge: CrossProcessBridge) {
|
||||
/* Use custom title bar. Take the sn-titlebar-height off of
|
||||
the app content height so its not overflowing */
|
||||
sheet.insertRule(
|
||||
'[role="dialog"] { height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; top: var(--sn-desktop-titlebar-height); }',
|
||||
'[role="dialog"] { height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; margin-top: var(--sn-desktop-titlebar-height); }',
|
||||
sheet.cssRules.length,
|
||||
)
|
||||
sheet.insertRule(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.108.103",
|
||||
"version": "3.108.118",
|
||||
"license": "CC BY-NC-SA 4.0",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -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.21.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.21.70",
|
||||
"version": "1.21.71",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.28.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.81](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.80](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.28.80",
|
||||
"version": "1.28.82",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.17.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
# [1.17.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
### Features
|
||||
|
||||
* Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML ([#2433](https://github.com/standardnotes/app/issues/2433)) ([ca9895c](https://github.com/standardnotes/app/commit/ca9895cac117aad16cd2f89633d7613ed54b67bf))
|
||||
|
||||
## [1.16.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.16.26",
|
||||
"version": "1.17.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export interface SuperConverterServiceInterface {
|
||||
convertString: (superString: string, toFormat: 'txt' | 'md' | 'html' | 'json') => string
|
||||
isValidSuperString(superString: string): boolean
|
||||
convertSuperStringToOtherFormat: (superString: string, toFormat: 'txt' | 'md' | 'html' | 'json') => string
|
||||
convertOtherFormatToSuperString: (otherFormatString: string, fromFormat: 'txt' | 'md' | 'html' | 'json') => string
|
||||
}
|
||||
|
||||
@@ -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.56.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.95](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.88](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.85](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.84](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.83](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -723,7 +723,7 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||
boost: 57d2868c099736d80fcd648bf211b4431e51a558
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
FBLazyVector: 4cce221dd782d3ff7c4172167bba09d58af67ccb
|
||||
@@ -743,7 +743,7 @@ SPEC CHECKSUMS:
|
||||
MMKV: 9c4663aa7ca255d478ff10f2f5cb7d17c1651ccd
|
||||
MMKVCore: 89f5c8a66bba2dcd551779dea4d412eeec8ff5bb
|
||||
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
|
||||
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
|
||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||
RCTRequired: a2faf4bad4e438ca37b2040cb8f7799baa065c18
|
||||
RCTTypeSafety: cb09f3e4747b6d18331a15eb05271de7441ca0b3
|
||||
React: 13109005b5353095c052f26af37413340ccf7a5d
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.56.82",
|
||||
"version": "3.56.97",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "CC BY-NC-SA 4.0",
|
||||
|
||||
@@ -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.47.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.47.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.47.7",
|
||||
"version": "1.47.8",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
|
||||
## [1.4.470](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.469](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.468](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.467](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.466](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.465](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.464](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.463](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.462](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.461](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.460](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.459](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.458](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.457](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.456](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.455](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.455",
|
||||
"version": "1.4.470",
|
||||
"license": "CC BY-NC-SA 4.0",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -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.13.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.37](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.13.37",
|
||||
"version": "1.13.38",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,6 @@ export interface SharedVaultServerHash {
|
||||
uuid: string
|
||||
user_uuid: string
|
||||
file_upload_bytes_used: number
|
||||
file_upload_bytes_limit: number
|
||||
created_at_timestamp: number
|
||||
updated_at_timestamp: number
|
||||
}
|
||||
|
||||
@@ -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.64.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
# [1.64.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
### Features
|
||||
|
||||
* Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML ([#2433](https://github.com/standardnotes/app/issues/2433)) ([ca9895c](https://github.com/standardnotes/app/commit/ca9895cac117aad16cd2f89633d7613ed54b67bf))
|
||||
|
||||
## [1.63.38](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.63.38",
|
||||
"version": "1.64.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -460,7 +460,10 @@ export class FilesBackupService
|
||||
for (const note of notes) {
|
||||
const tags = this.items.getSortedTagsForItem(note)
|
||||
const tagNames = tags.map((tag) => this.items.getTagLongTitle(tag))
|
||||
const text = note.noteType === NoteType.Super ? this.markdownConverter.convertString(note.text, 'md') : note.text
|
||||
const text =
|
||||
note.noteType === NoteType.Super
|
||||
? this.markdownConverter.convertSuperStringToOtherFormat(note.text, 'md')
|
||||
: note.text
|
||||
await this.device.savePlaintextNoteBackup(location, note.uuid, note.title, tagNames, text)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ export class FileService extends AbstractService implements FilesClientInterface
|
||||
unencryptedFileSizeForUpload?: number | undefined
|
||||
moveOperationType?: SharedVaultMoveType
|
||||
sharedVaultToSharedVaultMoveTargetUuid?: string
|
||||
sharedVaultOwnerUuid?: string
|
||||
}): Promise<string | ClientDisplayableError> {
|
||||
if (params.operation !== ValetTokenOperation.Write && !params.fileUuidRequiredForExistingFiles) {
|
||||
throw new Error('File UUID is required for for non-write operations')
|
||||
@@ -114,6 +115,7 @@ export class FileService extends AbstractService implements FilesClientInterface
|
||||
|
||||
const valetTokenResponse = await this.sharedVault.createSharedVaultFileValetToken({
|
||||
sharedVaultUuid: params.sharedVaultUuid,
|
||||
sharedVaultOwnerUuid: params.sharedVaultUuid,
|
||||
fileUuid: params.fileUuidRequiredForExistingFiles,
|
||||
remoteIdentifier: params.remoteIdentifier,
|
||||
operation: params.operation,
|
||||
@@ -135,6 +137,7 @@ export class FileService extends AbstractService implements FilesClientInterface
|
||||
): Promise<void | ClientDisplayableError> {
|
||||
const valetTokenResult = await this.createSharedVaultValetToken({
|
||||
sharedVaultUuid: file.shared_vault_uuid ? file.shared_vault_uuid : sharedVault.sharing.sharedVaultUuid,
|
||||
sharedVaultOwnerUuid: sharedVault.sharing.ownerUserUuid,
|
||||
remoteIdentifier: file.remoteIdentifier,
|
||||
operation: ValetTokenOperation.Move,
|
||||
fileUuidRequiredForExistingFiles: file.uuid,
|
||||
@@ -186,6 +189,7 @@ export class FileService extends AbstractService implements FilesClientInterface
|
||||
vault && vault.isSharedVaultListing()
|
||||
? await this.createSharedVaultValetToken({
|
||||
sharedVaultUuid: vault.sharing.sharedVaultUuid,
|
||||
sharedVaultOwnerUuid: vault.sharing.ownerUserUuid,
|
||||
remoteIdentifier,
|
||||
operation: ValetTokenOperation.Write,
|
||||
unencryptedFileSizeForUpload: sizeInBytes,
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ describe('SyncLocalVaultsWithRemoteSharedVaults', () => {
|
||||
uuid: '1-2-3',
|
||||
user_uuid: '2-3-4',
|
||||
file_upload_bytes_used: 123,
|
||||
file_upload_bytes_limit: 10000000,
|
||||
created_at_timestamp: 123,
|
||||
updated_at_timestamp: 123,
|
||||
}] } })
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.202.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.202.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.202.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.202.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
@@ -318,7 +318,9 @@ export class LegacyApiService
|
||||
}
|
||||
|
||||
signOut(): Promise<HttpResponse<SignOutResponse>> {
|
||||
return this.httpService.post<SignOutResponse>(Paths.v1.signOut, undefined, this.getSessionAccessToken())
|
||||
return this.httpService.post<SignOutResponse>(Paths.v1.signOut, undefined, {
|
||||
authentication: this.getSessionAccessToken(),
|
||||
})
|
||||
}
|
||||
|
||||
async changeCredentials(parameters: {
|
||||
@@ -344,7 +346,9 @@ export class LegacyApiService
|
||||
...parameters.newKeyParams.getPortableValue(),
|
||||
})
|
||||
|
||||
const response = await this.httpService.put<ChangeCredentialsResponse>(path, params, this.getSessionAccessToken())
|
||||
const response = await this.httpService.put<ChangeCredentialsResponse>(path, params, {
|
||||
authentication: this.getSessionAccessToken(),
|
||||
})
|
||||
|
||||
this.changing = false
|
||||
|
||||
@@ -481,7 +485,11 @@ export class LegacyApiService
|
||||
return preprocessingError
|
||||
}
|
||||
const path = Paths.v1.sessions
|
||||
const response = await this.httpService.get<SessionListResponse>(path, {}, this.getSessionAccessToken())
|
||||
const response = await this.httpService.get<SessionListResponse>(
|
||||
path,
|
||||
{},
|
||||
{ authentication: this.getSessionAccessToken() },
|
||||
)
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
this.preprocessAuthenticatedErrorResponse(response)
|
||||
@@ -502,7 +510,7 @@ export class LegacyApiService
|
||||
const response = await this.httpService.delete<SessionListResponse>(
|
||||
path,
|
||||
{ uuid: sessionId },
|
||||
this.getSessionAccessToken(),
|
||||
{ authentication: this.getSessionAccessToken() },
|
||||
)
|
||||
|
||||
if (isErrorResponse(response)) {
|
||||
|
||||
@@ -35,12 +35,12 @@ describe('features', () => {
|
||||
|
||||
describe('new user roles received on api response meta', () => {
|
||||
it('should save roles and features', async () => {
|
||||
expect(application.features.onlineRoles).to.have.lengthOf(1)
|
||||
expect(application.features.onlineRoles).to.have.lengthOf.above(0)
|
||||
expect(application.features.onlineRoles[0]).to.equal('CORE_USER')
|
||||
|
||||
const storedRoles = await application.getValue(StorageKey.UserRoles)
|
||||
|
||||
expect(storedRoles).to.have.lengthOf(1)
|
||||
expect(storedRoles).to.have.lengthOf.above(0)
|
||||
expect(storedRoles[0]).to.equal('CORE_USER')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
<script type="module">
|
||||
import MainRegistry from './TestRegistry/MainRegistry.js'
|
||||
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
const vaultTestsEnabled = urlSearchParams.get('vaults') === 'enabled' ? true : false;
|
||||
MainRegistry.VaultTests.enabled = MainRegistry.VaultTests.enabled || vaultTestsEnabled;
|
||||
|
||||
const loadTest = (fileName) => {
|
||||
return new Promise((resolve) => {
|
||||
const script = document.createElement('script');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.202.49",
|
||||
"version": "2.202.52",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.30.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
# [1.30.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
### Features
|
||||
|
||||
* Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML ([#2433](https://github.com/standardnotes/app/issues/2433)) ([ca9895c](https://github.com/standardnotes/app/commit/ca9895cac117aad16cd2f89633d7613ed54b67bf))
|
||||
|
||||
## [1.29.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.29.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.29.16",
|
||||
"version": "1.30.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -2,37 +2,56 @@
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { jsonTestData, htmlTestData } from './testData'
|
||||
import { jsonTextContentData, htmlTestData, jsonListContentData } from './testData'
|
||||
import { GoogleKeepConverter } from './GoogleKeepConverter'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/snjs'
|
||||
|
||||
describe('GoogleKeepConverter', () => {
|
||||
const crypto = {
|
||||
generateUUID: () => String(Math.random()),
|
||||
} as unknown as PureCryptoInterface
|
||||
|
||||
const superConverterService: SuperConverterServiceInterface = {
|
||||
isValidSuperString: () => true,
|
||||
convertOtherFormatToSuperString: (data: string) => data,
|
||||
convertSuperStringToOtherFormat: (data: string) => data,
|
||||
}
|
||||
const generateUuid = new GenerateUuid(crypto)
|
||||
|
||||
it('should parse json data', () => {
|
||||
const converter = new GoogleKeepConverter(generateUuid)
|
||||
const converter = new GoogleKeepConverter(superConverterService, generateUuid)
|
||||
|
||||
const result = converter.tryParseAsJson(jsonTestData)
|
||||
const textContent = converter.tryParseAsJson(jsonTextContentData, false)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.created_at).toBeInstanceOf(Date)
|
||||
expect(result?.updated_at).toBeInstanceOf(Date)
|
||||
expect(result?.uuid).not.toBeNull()
|
||||
expect(result?.content_type).toBe('Note')
|
||||
expect(result?.content.title).toBe('Testing 1')
|
||||
expect(result?.content.text).toBe('This is a test.')
|
||||
expect(result?.content.trashed).toBe(false)
|
||||
expect(result?.content.archived).toBe(false)
|
||||
expect(result?.content.pinned).toBe(false)
|
||||
expect(textContent).not.toBeNull()
|
||||
expect(textContent?.created_at).toBeInstanceOf(Date)
|
||||
expect(textContent?.updated_at).toBeInstanceOf(Date)
|
||||
expect(textContent?.uuid).not.toBeNull()
|
||||
expect(textContent?.content_type).toBe('Note')
|
||||
expect(textContent?.content.title).toBe('Testing 1')
|
||||
expect(textContent?.content.text).toBe('This is a test.')
|
||||
expect(textContent?.content.trashed).toBe(false)
|
||||
expect(textContent?.content.archived).toBe(false)
|
||||
expect(textContent?.content.pinned).toBe(false)
|
||||
|
||||
const listContent = converter.tryParseAsJson(jsonListContentData, false)
|
||||
|
||||
expect(listContent).not.toBeNull()
|
||||
expect(listContent?.created_at).toBeInstanceOf(Date)
|
||||
expect(listContent?.updated_at).toBeInstanceOf(Date)
|
||||
expect(listContent?.uuid).not.toBeNull()
|
||||
expect(listContent?.content_type).toBe('Note')
|
||||
expect(listContent?.content.title).toBe('Testing 1')
|
||||
expect(listContent?.content.text).toBe('- [ ] Test 1\n- [x] Test 2')
|
||||
expect(textContent?.content.trashed).toBe(false)
|
||||
expect(textContent?.content.archived).toBe(false)
|
||||
expect(textContent?.content.pinned).toBe(false)
|
||||
})
|
||||
|
||||
it('should parse html data', () => {
|
||||
const converter = new GoogleKeepConverter(generateUuid)
|
||||
const converter = new GoogleKeepConverter(superConverterService, generateUuid)
|
||||
|
||||
const result = converter.tryParseAsHtml(
|
||||
htmlTestData,
|
||||
|
||||
@@ -2,33 +2,48 @@ import { ContentType } from '@standardnotes/domain-core'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/files'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
|
||||
type Content =
|
||||
| {
|
||||
textContent: string
|
||||
}
|
||||
| {
|
||||
listContent: {
|
||||
text: string
|
||||
isChecked: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
type GoogleKeepJsonNote = {
|
||||
color: string
|
||||
isTrashed: boolean
|
||||
isPinned: boolean
|
||||
isArchived: boolean
|
||||
textContent: string
|
||||
title: string
|
||||
userEditedTimestampUsec: number
|
||||
}
|
||||
} & Content
|
||||
|
||||
export class GoogleKeepConverter {
|
||||
constructor(private _generateUuid: GenerateUuid) {}
|
||||
constructor(
|
||||
private superConverterService: SuperConverterServiceInterface,
|
||||
private _generateUuid: GenerateUuid,
|
||||
) {}
|
||||
|
||||
async convertGoogleKeepBackupFileToNote(
|
||||
file: File,
|
||||
stripHtml: boolean,
|
||||
isEntitledToSuper: boolean,
|
||||
): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const possiblePayloadFromJson = this.tryParseAsJson(content)
|
||||
const possiblePayloadFromJson = this.tryParseAsJson(content, isEntitledToSuper)
|
||||
|
||||
if (possiblePayloadFromJson) {
|
||||
return possiblePayloadFromJson
|
||||
}
|
||||
|
||||
const possiblePayloadFromHtml = this.tryParseAsHtml(content, file, stripHtml)
|
||||
const possiblePayloadFromHtml = this.tryParseAsHtml(content, file, isEntitledToSuper)
|
||||
|
||||
if (possiblePayloadFromHtml) {
|
||||
return possiblePayloadFromHtml
|
||||
@@ -37,20 +52,51 @@ export class GoogleKeepConverter {
|
||||
throw new Error('Could not parse Google Keep backup file')
|
||||
}
|
||||
|
||||
tryParseAsHtml(data: string, file: { name: string }, stripHtml: boolean): DecryptedTransferPayload<NoteContent> {
|
||||
tryParseAsHtml(
|
||||
data: string,
|
||||
file: { name: string },
|
||||
isEntitledToSuper: boolean,
|
||||
): DecryptedTransferPayload<NoteContent> {
|
||||
const rootElement = document.createElement('html')
|
||||
rootElement.innerHTML = data
|
||||
|
||||
const headingElement = rootElement.getElementsByClassName('heading')[0]
|
||||
const date = new Date(headingElement?.textContent || '')
|
||||
headingElement?.remove()
|
||||
|
||||
const contentElement = rootElement.getElementsByClassName('content')[0]
|
||||
if (!contentElement) {
|
||||
throw new Error('Could not parse content. Content element not found.')
|
||||
}
|
||||
|
||||
let content: string | null
|
||||
|
||||
// Replace <br> with \n so line breaks get recognised
|
||||
contentElement.innerHTML = contentElement.innerHTML.replace(/<br>/g, '\n')
|
||||
// Convert lists to readable plaintext format
|
||||
// or Super-convertable format
|
||||
const lists = contentElement.getElementsByTagName('ul')
|
||||
Array.from(lists).forEach((list) => {
|
||||
list.setAttribute('__lexicallisttype', 'check')
|
||||
|
||||
if (stripHtml) {
|
||||
const items = list.getElementsByTagName('li')
|
||||
Array.from(items).forEach((item) => {
|
||||
const bulletSpan = item.getElementsByClassName('bullet')[0]
|
||||
bulletSpan?.remove()
|
||||
|
||||
const checked = item.classList.contains('checked')
|
||||
item.setAttribute('aria-checked', checked ? 'true' : 'false')
|
||||
|
||||
if (!isEntitledToSuper) {
|
||||
item.textContent = `- ${checked ? '[x]' : '[ ]'} ${item.textContent?.trim()}\n`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!isEntitledToSuper) {
|
||||
// Replace <br> with \n so line breaks get recognised
|
||||
contentElement.innerHTML = contentElement.innerHTML.replace(/<br>/g, '\n')
|
||||
content = contentElement.textContent
|
||||
} else {
|
||||
content = contentElement.innerHTML
|
||||
content = this.superConverterService.convertOtherFormatToSuperString(rootElement.innerHTML, 'html')
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
@@ -59,8 +105,6 @@ export class GoogleKeepConverter {
|
||||
|
||||
const title = rootElement.getElementsByClassName('title')[0]?.textContent || file.name
|
||||
|
||||
const date = this.getDateFromGKeepNote(data) || new Date()
|
||||
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
@@ -72,35 +116,30 @@ export class GoogleKeepConverter {
|
||||
title: title,
|
||||
text: content,
|
||||
references: [],
|
||||
...(isEntitledToSuper
|
||||
? {
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
getDateFromGKeepNote(note: string) {
|
||||
const regexWithTitle = /.*(?=<\/div>\n<div class="title">)/
|
||||
const regexWithoutTitle = /.*(?=<\/div>\n\n<div class="content">)/
|
||||
const possibleDateStringWithTitle = regexWithTitle.exec(note)?.[0]
|
||||
const possibleDateStringWithoutTitle = regexWithoutTitle.exec(note)?.[0]
|
||||
if (possibleDateStringWithTitle) {
|
||||
const date = new Date(possibleDateStringWithTitle)
|
||||
if (date.toString() !== 'Invalid Date' && date.toString() !== 'NaN') {
|
||||
return date
|
||||
}
|
||||
}
|
||||
if (possibleDateStringWithoutTitle) {
|
||||
const date = new Date(possibleDateStringWithoutTitle)
|
||||
if (date.toString() !== 'Invalid Date' && date.toString() !== 'NaN') {
|
||||
return date
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
static isValidGoogleKeepJson(json: any): boolean {
|
||||
if (typeof json.textContent !== 'string') {
|
||||
if (typeof json.listContent === 'object' && Array.isArray(json.listContent)) {
|
||||
return json.listContent.every(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(item: any) => typeof item.text === 'string' && typeof item.isChecked === 'boolean',
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
typeof json.title === 'string' &&
|
||||
typeof json.textContent === 'string' &&
|
||||
typeof json.userEditedTimestampUsec === 'number' &&
|
||||
typeof json.isArchived === 'boolean' &&
|
||||
typeof json.isTrashed === 'boolean' &&
|
||||
@@ -109,13 +148,26 @@ export class GoogleKeepConverter {
|
||||
)
|
||||
}
|
||||
|
||||
tryParseAsJson(data: string): DecryptedTransferPayload<NoteContent> | null {
|
||||
tryParseAsJson(data: string, isEntitledToSuper: boolean): DecryptedTransferPayload<NoteContent> | null {
|
||||
try {
|
||||
const parsed = JSON.parse(data) as GoogleKeepJsonNote
|
||||
if (!GoogleKeepConverter.isValidGoogleKeepJson(parsed)) {
|
||||
return null
|
||||
}
|
||||
const date = new Date(parsed.userEditedTimestampUsec / 1000)
|
||||
let text: string
|
||||
if ('textContent' in parsed) {
|
||||
text = parsed.textContent
|
||||
} else {
|
||||
text = parsed.listContent
|
||||
.map((item) => {
|
||||
return item.isChecked ? `- [x] ${item.text}` : `- [ ] ${item.text}`
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
if (isEntitledToSuper) {
|
||||
text = this.superConverterService.convertOtherFormatToSuperString(text, 'md')
|
||||
}
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
@@ -125,14 +177,21 @@ export class GoogleKeepConverter {
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: parsed.title,
|
||||
text: parsed.textContent,
|
||||
text,
|
||||
references: [],
|
||||
archived: Boolean(parsed.isArchived),
|
||||
trashed: Boolean(parsed.isTrashed),
|
||||
pinned: Boolean(parsed.isPinned),
|
||||
...(isEntitledToSuper
|
||||
? {
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const json = {
|
||||
const jsonWithTextContent = {
|
||||
color: 'DEFAULT',
|
||||
isTrashed: false,
|
||||
isPinned: false,
|
||||
@@ -8,7 +8,28 @@ const json = {
|
||||
userEditedTimestampUsec: 1618528050144000,
|
||||
}
|
||||
|
||||
export const jsonTestData = JSON.stringify(json)
|
||||
export const jsonTextContentData = JSON.stringify(jsonWithTextContent)
|
||||
|
||||
const jsonWithListContent = {
|
||||
color: 'DEFAULT',
|
||||
isTrashed: false,
|
||||
isPinned: false,
|
||||
isArchived: false,
|
||||
listContent: [
|
||||
{
|
||||
text: 'Test 1',
|
||||
isChecked: false,
|
||||
},
|
||||
{
|
||||
text: 'Test 2',
|
||||
isChecked: true,
|
||||
},
|
||||
],
|
||||
title: 'Testing 1',
|
||||
userEditedTimestampUsec: 1618528050144000,
|
||||
}
|
||||
|
||||
export const jsonListContentData = JSON.stringify(jsonWithListContent)
|
||||
|
||||
export const htmlTestData = `<?xml version="1.0" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/files'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { readFileAsText } from '../Utils'
|
||||
|
||||
export class HTMLConverter {
|
||||
constructor(
|
||||
private superConverterService: SuperConverterServiceInterface,
|
||||
private _generateUuid: GenerateUuid,
|
||||
) {}
|
||||
|
||||
static isHTMLFile(file: File): boolean {
|
||||
return file.type === 'text/html'
|
||||
}
|
||||
|
||||
async convertHTMLFileToNote(file: File, isEntitledToSuper: boolean): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const { name } = parseFileName(file.name)
|
||||
|
||||
const createdAtDate = file.lastModified ? new Date(file.lastModified) : new Date()
|
||||
const updatedAtDate = file.lastModified ? new Date(file.lastModified) : new Date()
|
||||
|
||||
const text = isEntitledToSuper
|
||||
? this.superConverterService.convertOtherFormatToSuperString(content, 'html')
|
||||
: content
|
||||
|
||||
return {
|
||||
created_at: createdAtDate,
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this._generateUuid.execute().getValue(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: name,
|
||||
text,
|
||||
references: [],
|
||||
...(isEntitledToSuper
|
||||
? {
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,11 @@ import { PlaintextConverter } from './PlaintextConverter/PlaintextConverter'
|
||||
import { SimplenoteConverter } from './SimplenoteConverter/SimplenoteConverter'
|
||||
import { readFileAsText } from './Utils'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { HTMLConverter } from './HTMLConverter/HTMLConverter'
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/snjs/dist/@types'
|
||||
import { SuperConverter } from './SuperConverter/SuperConverter'
|
||||
|
||||
export type NoteImportType = 'plaintext' | 'evernote' | 'google-keep' | 'simplenote' | 'aegis'
|
||||
export type NoteImportType = 'plaintext' | 'evernote' | 'google-keep' | 'simplenote' | 'aegis' | 'html' | 'super'
|
||||
|
||||
export class Importer {
|
||||
aegisConverter: AegisToAuthenticatorConverter
|
||||
@@ -23,21 +26,26 @@ export class Importer {
|
||||
simplenoteConverter: SimplenoteConverter
|
||||
plaintextConverter: PlaintextConverter
|
||||
evernoteConverter: EvernoteConverter
|
||||
htmlConverter: HTMLConverter
|
||||
superConverter: SuperConverter
|
||||
|
||||
constructor(
|
||||
private features: FeaturesClientInterface,
|
||||
private mutator: MutatorClientInterface,
|
||||
private items: ItemManagerInterface,
|
||||
private superConverterService: SuperConverterServiceInterface,
|
||||
_generateUuid: GenerateUuid,
|
||||
) {
|
||||
this.aegisConverter = new AegisToAuthenticatorConverter(_generateUuid)
|
||||
this.googleKeepConverter = new GoogleKeepConverter(_generateUuid)
|
||||
this.googleKeepConverter = new GoogleKeepConverter(this.superConverterService, _generateUuid)
|
||||
this.simplenoteConverter = new SimplenoteConverter(_generateUuid)
|
||||
this.plaintextConverter = new PlaintextConverter(_generateUuid)
|
||||
this.evernoteConverter = new EvernoteConverter(_generateUuid)
|
||||
this.htmlConverter = new HTMLConverter(this.superConverterService, _generateUuid)
|
||||
this.superConverter = new SuperConverter(this.superConverterService, _generateUuid)
|
||||
}
|
||||
|
||||
static detectService = async (file: File): Promise<NoteImportType | null> => {
|
||||
detectService = async (file: File): Promise<NoteImportType | null> => {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const { ext } = parseFileName(file.name)
|
||||
@@ -64,28 +72,47 @@ export class Importer {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (file.type === 'application/json' && this.superConverterService.isValidSuperString(content)) {
|
||||
return 'super'
|
||||
}
|
||||
|
||||
if (PlaintextConverter.isValidPlaintextFile(file)) {
|
||||
return 'plaintext'
|
||||
}
|
||||
|
||||
if (HTMLConverter.isHTMLFile(file)) {
|
||||
return 'html'
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async getPayloadsFromFile(file: File, type: NoteImportType): Promise<DecryptedTransferPayload[]> {
|
||||
if (type === 'aegis') {
|
||||
const isEntitledToSuper =
|
||||
this.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SuperEditor).getValue(),
|
||||
) === FeatureStatus.Entitled
|
||||
if (type === 'super') {
|
||||
if (!isEntitledToSuper) {
|
||||
throw new Error('Importing Super notes requires a subscription.')
|
||||
}
|
||||
return [await this.superConverter.convertSuperFileToNote(file)]
|
||||
} else if (type === 'aegis') {
|
||||
const isEntitledToAuthenticator =
|
||||
this.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.TokenVaultEditor).getValue(),
|
||||
) === FeatureStatus.Entitled
|
||||
return [await this.aegisConverter.convertAegisBackupFileToNote(file, isEntitledToAuthenticator)]
|
||||
} else if (type === 'google-keep') {
|
||||
return [await this.googleKeepConverter.convertGoogleKeepBackupFileToNote(file, true)]
|
||||
return [await this.googleKeepConverter.convertGoogleKeepBackupFileToNote(file, isEntitledToSuper)]
|
||||
} else if (type === 'simplenote') {
|
||||
return await this.simplenoteConverter.convertSimplenoteBackupFileToNotes(file)
|
||||
} else if (type === 'evernote') {
|
||||
return await this.evernoteConverter.convertENEXFileToNotesAndTags(file, false)
|
||||
} else if (type === 'plaintext') {
|
||||
return [await this.plaintextConverter.convertPlaintextFileToNote(file)]
|
||||
} else if (type === 'html') {
|
||||
return [await this.htmlConverter.convertHTMLFileToNote(file, isEntitledToSuper)]
|
||||
}
|
||||
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/files'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { parseFileName } from '@standardnotes/filepicker'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
|
||||
export class SuperConverter {
|
||||
constructor(
|
||||
private converterService: SuperConverterServiceInterface,
|
||||
private _generateUuid: GenerateUuid,
|
||||
) {}
|
||||
|
||||
async convertSuperFileToNote(file: File): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
if (!this.converterService.isValidSuperString(content)) {
|
||||
throw new Error('Content is not valid Super JSON')
|
||||
}
|
||||
|
||||
const { name } = parseFileName(file.name)
|
||||
|
||||
const createdAtDate = file.lastModified ? new Date(file.lastModified) : new Date()
|
||||
const updatedAtDate = file.lastModified ? new Date(file.lastModified) : new Date()
|
||||
|
||||
return {
|
||||
created_at: createdAtDate,
|
||||
created_at_timestamp: createdAtDate.getTime(),
|
||||
updated_at: updatedAtDate,
|
||||
updated_at_timestamp: updatedAtDate.getTime(),
|
||||
uuid: this._generateUuid.execute().getValue(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: name,
|
||||
text: content,
|
||||
references: [],
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,10 +337,11 @@ export class ThemeManager extends AbstractUIService {
|
||||
link.onload = () => {
|
||||
this.syncThemeColorMetadata()
|
||||
|
||||
if (this.application.isNativeMobileWeb() && !theme.layerable) {
|
||||
const packageInfo = theme.featureDescription
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
setTimeout(() => {
|
||||
this.application.mobileDevice.handleThemeSchemeChange(packageInfo.isDark ?? false, this.getBackgroundColor())
|
||||
const backgroundColorString = this.getBackgroundColor()
|
||||
const backgroundColor = new Color(backgroundColorString)
|
||||
this.application.mobileDevice.handleThemeSchemeChange(backgroundColor.isDark(), backgroundColorString)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,75 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.171.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.171.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.171.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where dragging a list item with a link in Super would only re-order the link ([d794847](https://github.com/standardnotes/app/commit/d79484739b2a324f09cb821c39f402f8c65d477e))
|
||||
|
||||
# [3.171.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)
|
||||
|
||||
### Features
|
||||
|
||||
* Add toggle to disable creating a new tag on import ([f26ad41](https://github.com/standardnotes/app/commit/f26ad410e2888cb90e34c25d19d746f54db1e53e))
|
||||
* Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML ([#2433](https://github.com/standardnotes/app/issues/2433)) ([ca9895c](https://github.com/standardnotes/app/commit/ca9895cac117aad16cd2f89633d7613ed54b67bf))
|
||||
|
||||
## [3.170.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.170.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.170.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.170.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
# [3.170.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)
|
||||
|
||||
### Features
|
||||
|
||||
* Super formatting toolbar on mobile now shows whether an option is active in the selection, and also shows hints when an option is long-pressed ([#2432](https://github.com/standardnotes/app/issues/2432)) ([77f72ff](https://github.com/standardnotes/app/commit/77f72ff7b67a5dab502d1db95dc512e3bf348541))
|
||||
|
||||
## [3.169.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.169.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.169.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.169.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.169.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.169.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed issue where note context menu would not open if right-clicking multiple times ([5af0ff8](https://github.com/standardnotes/app/commit/5af0ff8f2eba32bce46f4e2359e9198f86bf7f4e))
|
||||
|
||||
## [3.169.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
@@ -1,5 +1,184 @@
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"version": "3.171.3",
|
||||
"title": "[3.171.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-21)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.171.2",
|
||||
"title": "[3.171.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.171.1",
|
||||
"title": "[3.171.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)",
|
||||
"date": null,
|
||||
"body": "### Bug Fixes\n\n* Fixed issue where dragging a list item with a link in Super would only re-order the link ([d794847](https://github.com/standardnotes/app/commit/d79484739b2a324f09cb821c39f402f8c65d477e))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Fixed issue where dragging a list item with a link in Super would only re-order the link (d794847)"
|
||||
],
|
||||
"Bug Fixes": [
|
||||
"Fixed issue where dragging a list item with a link in Super would only re-order the link (d794847)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.171.0",
|
||||
"title": "[3.171.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-18)",
|
||||
"date": null,
|
||||
"body": "### Features\n\n* Add toggle to disable creating a new tag on import ([f26ad41](https://github.com/standardnotes/app/commit/f26ad410e2888cb90e34c25d19d746f54db1e53e))\n* Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML ([#2433](https://github.com/standardnotes/app/issues/2433)) ([ca9895c](https://github.com/standardnotes/app/commit/ca9895cac117aad16cd2f89633d7613ed54b67bf))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Add toggle to disable creating a new tag on import (f26ad41)",
|
||||
"Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML (#2433) (ca9895c)"
|
||||
],
|
||||
"Features": [
|
||||
"Add toggle to disable creating a new tag on import (f26ad41)",
|
||||
"Added Super & HTML import options in Import modal. Google Keep notes will now also be imported as Super notes, with attachments if importing from HTML (#2433) (ca9895c)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.170.4",
|
||||
"title": "[3.170.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.170.3",
|
||||
"title": "[3.170.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-17)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.170.2",
|
||||
"title": "[3.170.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.170.1",
|
||||
"title": "[3.170.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.170.0",
|
||||
"title": "[3.170.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-16)",
|
||||
"date": null,
|
||||
"body": "### Features\n\n* Super formatting toolbar on mobile now shows whether an option is active in the selection, and also shows hints when an option is long-pressed ([#2432](https://github.com/standardnotes/app/issues/2432)) ([77f72ff](https://github.com/standardnotes/app/commit/77f72ff7b67a5dab502d1db95dc512e3bf348541))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Super formatting toolbar on mobile now shows whether an option is active in the selection, and also shows hints when an option is long-pressed (#2432) (77f72ff)"
|
||||
],
|
||||
"Features": [
|
||||
"Super formatting toolbar on mobile now shows whether an option is active in the selection, and also shows hints when an option is long-pressed (#2432) (77f72ff)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.35",
|
||||
"title": "[3.169.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.34",
|
||||
"title": "[3.169.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-15)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.33",
|
||||
"title": "[3.169.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.32",
|
||||
"title": "[3.169.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.31",
|
||||
"title": "[3.169.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-14)",
|
||||
"date": null,
|
||||
"body": "**Note:** Version bump only for package @standardnotes/web",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Note: Version bump only for package @standardnotes/web"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.30",
|
||||
"title": "[3.169.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)",
|
||||
"date": null,
|
||||
"body": "### Bug Fixes\n\n* Fixed issue where note context menu would not open if right-clicking multiple times ([5af0ff8](https://github.com/standardnotes/app/commit/5af0ff8f2eba32bce46f4e2359e9198f86bf7f4e))",
|
||||
"parsed": {
|
||||
"_": [
|
||||
"Fixed issue where note context menu would not open if right-clicking multiple times (5af0ff8)"
|
||||
],
|
||||
"Bug Fixes": [
|
||||
"Fixed issue where note context menu would not open if right-clicking multiple times (5af0ff8)"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.169.29",
|
||||
"title": "[3.169.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-08-12)",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.169.29",
|
||||
"version": "3.171.3",
|
||||
"license": "CC BY-NC-SA 4.0",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
"author": "Standard Notes",
|
||||
"private": true,
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -51,7 +51,7 @@
|
||||
"@standardnotes/sncrypto-web": "workspace:*",
|
||||
"@standardnotes/snjs": "workspace:*",
|
||||
"@standardnotes/solarized-dark-theme": "^1.4.6",
|
||||
"@standardnotes/spreadsheets": "^1.8.0",
|
||||
"@standardnotes/spreadsheets": "^1.8.1",
|
||||
"@standardnotes/styles": "workspace:*",
|
||||
"@standardnotes/titanium-theme": "^1.4.7",
|
||||
"@standardnotes/toast": "workspace:*",
|
||||
|
||||
@@ -7,6 +7,7 @@ export const Web_TYPES = {
|
||||
AutolockService: Symbol.for('AutolockService'),
|
||||
ChangelogService: Symbol.for('ChangelogService'),
|
||||
DesktopManager: Symbol.for('DesktopManager'),
|
||||
SuperConverter: Symbol.for('SuperConverter'),
|
||||
Importer: Symbol.for('Importer'),
|
||||
ItemGroupController: Symbol.for('ItemGroupController'),
|
||||
KeyboardService: Symbol.for('KeyboardService'),
|
||||
|
||||
@@ -48,13 +48,24 @@ import { PanesForLayout } from '../UseCase/PanesForLayout'
|
||||
import { LoadPurchaseFlowUrl } from '../UseCase/LoadPurchaseFlowUrl'
|
||||
import { GetPurchaseFlowUrl } from '../UseCase/GetPurchaseFlowUrl'
|
||||
import { OpenSubscriptionDashboard } from '../UseCase/OpenSubscriptionDashboard'
|
||||
import { HeadlessSuperConverter } from '@/Components/SuperEditor/Tools/HeadlessSuperConverter'
|
||||
|
||||
export class WebDependencies extends DependencyContainer {
|
||||
constructor(private application: WebApplicationInterface) {
|
||||
super()
|
||||
|
||||
this.bind(Web_TYPES.SuperConverter, () => {
|
||||
return new HeadlessSuperConverter()
|
||||
})
|
||||
|
||||
this.bind(Web_TYPES.Importer, () => {
|
||||
return new Importer(application.features, application.mutator, application.items, application.generateUuid)
|
||||
return new Importer(
|
||||
application.features,
|
||||
application.mutator,
|
||||
application.items,
|
||||
this.get<HeadlessSuperConverter>(Web_TYPES.SuperConverter),
|
||||
application.generateUuid,
|
||||
)
|
||||
})
|
||||
|
||||
this.bind(Web_TYPES.IsNativeIOS, () => {
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ const WorkspaceSwitcherOption: FunctionComponent<Props> = ({ mainApplicationGrou
|
||||
<Popover
|
||||
title="Switch workspace"
|
||||
align="end"
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
className="py-2"
|
||||
open={isOpen}
|
||||
side="right"
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ const LockscreenWorkspaceSwitcher: FunctionComponent<Props> = ({ mainApplication
|
||||
<Popover
|
||||
title="Switch workspace"
|
||||
align="center"
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
className="py-2"
|
||||
open={isOpen}
|
||||
overrideZIndex="z-modal"
|
||||
|
||||
@@ -77,7 +77,7 @@ const ChangeEditorButton: FunctionComponent<Props> = ({ noteViewController, onCl
|
||||
title="Change note type"
|
||||
togglePopover={toggleMenu}
|
||||
disableClickOutside={isClickOutsideDisabled}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
className="pt-2 md:pt-0"
|
||||
>
|
||||
|
||||
@@ -23,7 +23,7 @@ const ChangeMultipleButton = ({ application, notesController }: Props) => {
|
||||
title="Change note type"
|
||||
togglePopover={toggleMenu}
|
||||
disableClickOutside={disableClickOutside}
|
||||
anchorElement={changeButtonRef.current}
|
||||
anchorElement={changeButtonRef}
|
||||
open={isChangeMenuOpen}
|
||||
className="pt-2 md:pt-0"
|
||||
>
|
||||
|
||||
+43
-41
@@ -67,47 +67,49 @@ const AddItemMenuButton = ({
|
||||
<Icon type="add" size="custom" className="h-5 w-5" />
|
||||
</button>
|
||||
</StyledTooltip>
|
||||
<Popover
|
||||
title="Add item"
|
||||
open={canShowMenu && isMenuOpen}
|
||||
anchorElement={addItemButtonRef.current}
|
||||
togglePopover={() => {
|
||||
setIsMenuOpen((isOpen) => !isOpen)
|
||||
}}
|
||||
side="bottom"
|
||||
align="center"
|
||||
className="py-2"
|
||||
>
|
||||
<Menu a11yLabel={'test'} isOpen={isMenuOpen}>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
addNewItem()
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="add" className="mr-2" />
|
||||
{addButtonLabel}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={async () => {
|
||||
setCaptureType('photo')
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="camera" className="mr-2" />
|
||||
Take photo
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={async () => {
|
||||
setCaptureType('video')
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="camera" className="mr-2" />
|
||||
Record video
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Popover>
|
||||
{canShowMenu && (
|
||||
<Popover
|
||||
title="Add item"
|
||||
open={isMenuOpen}
|
||||
anchorElement={addItemButtonRef}
|
||||
togglePopover={() => {
|
||||
setIsMenuOpen((isOpen) => !isOpen)
|
||||
}}
|
||||
side="bottom"
|
||||
align="center"
|
||||
className="py-2"
|
||||
>
|
||||
<Menu a11yLabel={'test'} isOpen={isMenuOpen}>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
addNewItem()
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="add" className="mr-2" />
|
||||
{addButtonLabel}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={async () => {
|
||||
setCaptureType('photo')
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="camera" className="mr-2" />
|
||||
Take photo
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={async () => {
|
||||
setCaptureType('video')
|
||||
setIsMenuOpen(false)
|
||||
}}
|
||||
>
|
||||
<Icon type="camera" className="mr-2" />
|
||||
Record video
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Popover>
|
||||
)}
|
||||
<ModalOverlay isOpen={captureType === 'photo'} close={closeCaptureModal}>
|
||||
<PhotoCaptureModal filesController={filesController} close={closeCaptureModal} />
|
||||
</ModalOverlay>
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ const ContentListHeader = ({
|
||||
/>
|
||||
<Popover
|
||||
open={showDisplayOptionsMenu}
|
||||
anchorElement={displayOptionsButtonRef.current}
|
||||
anchorElement={displayOptionsButtonRef}
|
||||
togglePopover={toggleDisplayOptionsMenu}
|
||||
align="start"
|
||||
className="py-2"
|
||||
|
||||
@@ -43,12 +43,10 @@ const NoteListItem: FunctionComponent<DisplayableListItemProps<SNNote>> = ({
|
||||
const hasFiles = application.items.itemsReferencingItem(item).filter(isFile).length > 0
|
||||
|
||||
const openNoteContextMenu = (posX: number, posY: number) => {
|
||||
notesController.setContextMenuOpen(false)
|
||||
notesController.setContextMenuClickLocation({
|
||||
x: posX,
|
||||
y: posY,
|
||||
})
|
||||
notesController.reloadContextMenuLayout()
|
||||
notesController.setContextMenuOpen(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ const ContextMenuCell = ({ items }: { items: DecryptedItemInterface[] }) => {
|
||||
<Popover
|
||||
title="File options"
|
||||
open={contextMenuVisible}
|
||||
anchorElement={anchorElementRef.current}
|
||||
anchorElement={anchorElementRef}
|
||||
togglePopover={() => {
|
||||
setContextMenuVisible(false)
|
||||
}}
|
||||
@@ -120,7 +120,7 @@ const ItemLinksCell = ({ item }: { item: DecryptedItemInterface }) => {
|
||||
<Popover
|
||||
title="Linked items"
|
||||
open={contextMenuVisible}
|
||||
anchorElement={anchorElementRef.current}
|
||||
anchorElement={anchorElementRef}
|
||||
togglePopover={() => {
|
||||
setContextMenuVisible(false)
|
||||
}}
|
||||
|
||||
@@ -19,13 +19,7 @@ const FilesOptionsPanel = ({ itemListController }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<RoundIconButton label="File options menu" onClick={toggleMenu} ref={buttonRef} icon="more" />
|
||||
<Popover
|
||||
title="File options"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
open={isOpen}
|
||||
className="py-2"
|
||||
>
|
||||
<Popover title="File options" togglePopover={toggleMenu} anchorElement={buttonRef} open={isOpen} className="py-2">
|
||||
<Menu a11yLabel="File options panel" isOpen={isOpen}>
|
||||
<FileMenuOptions
|
||||
selectedFiles={itemListController.selectedFiles}
|
||||
|
||||
@@ -212,7 +212,7 @@ const FilePreviewModal = observer(({ application }: Props) => {
|
||||
<Popover
|
||||
title="File options"
|
||||
open={showOptionsMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
anchorElement={menuButtonRef}
|
||||
togglePopover={closeOptionsMenu}
|
||||
side="bottom"
|
||||
align="start"
|
||||
|
||||
@@ -100,7 +100,7 @@ const FileViewWithoutProtection = ({ application, file }: FileViewProps) => {
|
||||
title="Details"
|
||||
open={isFileInfoPanelOpen}
|
||||
togglePopover={toggleFileInfoPanel}
|
||||
anchorElement={fileInfoButtonRef.current}
|
||||
anchorElement={fileInfoButtonRef}
|
||||
side="bottom"
|
||||
align="center"
|
||||
>
|
||||
|
||||
@@ -36,7 +36,7 @@ const AccountMenuButton = ({ hasError, controller, mainApplicationGroup, onClick
|
||||
</StyledTooltip>
|
||||
<Popover
|
||||
title="Account"
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
togglePopover={toggleMenu}
|
||||
side="top"
|
||||
|
||||
@@ -51,7 +51,7 @@ const QuickSettingsButton = ({ application, isMobileNavigation = false }: Props)
|
||||
<Popover
|
||||
title="Quick settings"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
side="top"
|
||||
align="start"
|
||||
|
||||
@@ -56,7 +56,7 @@ const VaultSelectionButton = ({ isMobileNavigation = false }: { isMobileNavigati
|
||||
<Popover
|
||||
title="Vault options"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
side="top"
|
||||
align="start"
|
||||
|
||||
@@ -6,11 +6,22 @@ import Modal, { ModalAction } from '../Modal/Modal'
|
||||
import ModalOverlay from '../Modal/ModalOverlay'
|
||||
import { ImportModalController } from '@/Controllers/ImportModalController'
|
||||
import { useApplication } from '../ApplicationProvider'
|
||||
import Switch from '../Switch/Switch'
|
||||
|
||||
const ImportModal = ({ importModalController }: { importModalController: ImportModalController }) => {
|
||||
const application = useApplication()
|
||||
|
||||
const { files, setFiles, updateFile, removeFile, parseAndImport, isVisible, close } = importModalController
|
||||
const {
|
||||
files,
|
||||
setFiles,
|
||||
shouldCreateTag,
|
||||
setShouldCreateTag,
|
||||
updateFile,
|
||||
removeFile,
|
||||
parseAndImport,
|
||||
isVisible,
|
||||
close,
|
||||
} = importModalController
|
||||
|
||||
const isReadyToImport = files.length > 0 && files.every((file) => file.status === 'ready')
|
||||
const importSuccessOrError =
|
||||
@@ -54,6 +65,12 @@ const ImportModal = ({ importModalController }: { importModalController: ImportM
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{files.length > 0 && (
|
||||
<label className="py-2 px-4 flex items-center gap-2 border-t border-border">
|
||||
<Switch checked={shouldCreateTag} onChange={setShouldCreateTag} />
|
||||
<span className="text-sm">Create tag with all imported notes</span>
|
||||
</label>
|
||||
)}
|
||||
</Modal>
|
||||
</ModalOverlay>
|
||||
)
|
||||
|
||||
@@ -11,6 +11,8 @@ const NoteImportTypeColors: Record<NoteImportType, string> = {
|
||||
'google-keep': 'bg-[#fbbd00] text-[#000]',
|
||||
aegis: 'bg-[#0d47a1] text-default',
|
||||
plaintext: 'bg-default border border-border',
|
||||
html: 'bg-accessory-tint-2',
|
||||
super: 'bg-accessory-tint-1 text-accessory-tint-1',
|
||||
}
|
||||
|
||||
const NoteImportTypeIcons: Record<NoteImportType, string> = {
|
||||
@@ -19,6 +21,8 @@ const NoteImportTypeIcons: Record<NoteImportType, string> = {
|
||||
'google-keep': 'gkeep',
|
||||
aegis: 'aegis',
|
||||
plaintext: 'plain-text',
|
||||
html: 'rich-text',
|
||||
super: 'file-doc',
|
||||
}
|
||||
|
||||
const ImportModalFileItem = ({
|
||||
@@ -53,13 +57,13 @@ const ImportModalFileItem = ({
|
||||
|
||||
useEffect(() => {
|
||||
const detect = async () => {
|
||||
const detectedService = await Importer.detectService(file.file)
|
||||
const detectedService = await importer.detectService(file.file)
|
||||
void setFileService(detectedService)
|
||||
}
|
||||
if (file.service === undefined) {
|
||||
void detect()
|
||||
}
|
||||
}, [file, setFileService])
|
||||
}, [file, importer, setFileService])
|
||||
|
||||
const notePayloads =
|
||||
file.status === 'ready' && file.payloads
|
||||
|
||||
@@ -5,12 +5,17 @@ import { observer } from 'mobx-react-lite'
|
||||
import { useCallback } from 'react'
|
||||
import Button from '../Button/Button'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useApplication } from '../ApplicationProvider'
|
||||
import { FeatureStatus, NativeFeatureIdentifier } from '@standardnotes/snjs'
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
|
||||
type Props = {
|
||||
setFiles: ImportModalController['setFiles']
|
||||
}
|
||||
|
||||
const ImportModalInitialPage = ({ setFiles }: Props) => {
|
||||
const application = useApplication()
|
||||
|
||||
const selectFiles = useCallback(
|
||||
async (service?: NoteImportType) => {
|
||||
const files = await ClassicFileReader.selectFiles()
|
||||
@@ -38,41 +43,46 @@ const ImportModalInitialPage = ({ setFiles }: Props) => {
|
||||
</button>
|
||||
<div className="text-center my-4 w-full">or import from:</div>
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<Button
|
||||
className="flex items-center bg-[#14cc45] !py-2 text-[#000]"
|
||||
primary
|
||||
onClick={() => selectFiles('evernote')}
|
||||
>
|
||||
<Icon type="evernote" className="mr-2" />
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('evernote')}>
|
||||
<Icon type="evernote" className="text-[#14cc45] mr-2" />
|
||||
Evernote
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center bg-[#fbbd00] !py-2 text-[#000]"
|
||||
primary
|
||||
onClick={() => selectFiles('google-keep')}
|
||||
>
|
||||
<Icon type="gkeep" className="mr-2" />
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('google-keep')}>
|
||||
<Icon type="gkeep" className="text-[#fbbd00] mr-2" />
|
||||
Google Keep
|
||||
</Button>
|
||||
<Button className="flex items-center bg-[#3360cc] !py-2" primary onClick={() => selectFiles('simplenote')}>
|
||||
<Icon type="simplenote" className="mr-2" />
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('simplenote')}>
|
||||
<Icon type="simplenote" className="text-[#3360cc] mr-2" />
|
||||
Simplenote
|
||||
</Button>
|
||||
<Button className="flex items-center bg-[#0d47a1] !py-2" primary onClick={() => selectFiles('aegis')}>
|
||||
<Icon type="aegis" className="mr-2" />
|
||||
Aegis Authenticator
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('aegis')}>
|
||||
<Icon type="aegis" className="bg-[#0d47a1] text-[#fff] rounded mr-2 p-1" size="normal" />
|
||||
Aegis
|
||||
</Button>
|
||||
<Button className="flex items-center bg-info !py-2" onClick={() => selectFiles('plaintext')} primary>
|
||||
<Icon type="plain-text" className="mr-2" />
|
||||
Plaintext
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('plaintext')}>
|
||||
<Icon type="plain-text" className="text-info mr-2" />
|
||||
Plaintext / Markdown
|
||||
</Button>
|
||||
<Button className="flex items-center !py-2" onClick={() => selectFiles('html')}>
|
||||
<Icon type="rich-text" className="text-accessory-tint-2 mr-2" />
|
||||
HTML
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center bg-accessory-tint-4 !py-2"
|
||||
primary
|
||||
onClick={() => selectFiles('plaintext')}
|
||||
className="flex items-center !py-2"
|
||||
onClick={() => {
|
||||
const isEntitledToSuper =
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SuperEditor).getValue(),
|
||||
) === FeatureStatus.Entitled
|
||||
if (!isEntitledToSuper) {
|
||||
application.showPremiumModal(FeatureName.Super)
|
||||
return
|
||||
}
|
||||
selectFiles('super').catch(console.error)
|
||||
}}
|
||||
>
|
||||
<Icon type="markdown" className="mr-2" />
|
||||
Markdown
|
||||
<Icon type="file-doc" className="text-accessory-tint-1 mr-2" />
|
||||
Super (JSON)
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -32,7 +32,7 @@ const LinkedItemsButton = ({ linkingController, onClickPreprocessing }: Props) =
|
||||
<Popover
|
||||
title="Linked items"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isLinkingPanelOpen}
|
||||
className="pb-2"
|
||||
>
|
||||
|
||||
@@ -101,7 +101,7 @@ export const LinkedItemsSectionItem = ({
|
||||
title="Options"
|
||||
open={isMenuOpen}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={menuButtonRef.current}
|
||||
anchorElement={menuButtonRef}
|
||||
side="bottom"
|
||||
align="center"
|
||||
className="py-2"
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
MouseEventHandler,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import Icon from '../Icon/Icon'
|
||||
@@ -27,12 +28,12 @@ const Tooltip = ({ text }: { text: string }) => {
|
||||
[visible],
|
||||
)
|
||||
|
||||
const [anchorElement, setAnchorElement] = useState<HTMLDivElement | null>(null)
|
||||
const anchorElement = useRef(null)
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div
|
||||
ref={setAnchorElement}
|
||||
ref={anchorElement}
|
||||
className={classNames('peer z-0 flex h-5 w-5 items-center justify-center rounded-full')}
|
||||
onClick={onClickMobile}
|
||||
onMouseEnter={() => setVisible(true)}
|
||||
|
||||
@@ -131,7 +131,7 @@ const Modal = ({
|
||||
<Popover
|
||||
title="Advanced"
|
||||
open={showAdvanced}
|
||||
anchorElement={advancedOptionRef.current}
|
||||
anchorElement={advancedOptionRef}
|
||||
disableMobileFullscreenTakeover={true}
|
||||
togglePopover={() => setShowAdvanced((show) => !show)}
|
||||
align="start"
|
||||
|
||||
@@ -78,7 +78,8 @@ const ModalOverlay = forwardRef(
|
||||
<Dialog
|
||||
tabIndex={0}
|
||||
className={classNames(
|
||||
'pointer-events-auto m-0 flex h-full w-full flex-col border-[--popover-border-color] bg-default md:bg-[--popover-background-color] md:[backdrop-filter:var(--popover-backdrop-filter)] p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
|
||||
'z-[1] pointer-events-auto m-0 flex h-full w-full flex-col border-[--popover-border-color] bg-default md:bg-[--popover-background-color] md:[backdrop-filter:var(--popover-backdrop-filter)] p-0 md:h-auto md:max-h-[85vh] md:w-160 md:rounded md:border md:shadow-main',
|
||||
'focus-visible:shadow-none focus-visible:outline-none',
|
||||
className,
|
||||
)}
|
||||
backdrop={
|
||||
|
||||
+2
-2
@@ -31,14 +31,14 @@ export const DiffView = ({
|
||||
const firstTitle = firstNote.title
|
||||
const firstText =
|
||||
firstNote.noteType === NoteType.Super && convertSuperToMarkdown
|
||||
? new HeadlessSuperConverter().convertString(firstNote.text, 'md')
|
||||
? new HeadlessSuperConverter().convertSuperStringToOtherFormat(firstNote.text, 'md')
|
||||
: firstNote.text
|
||||
|
||||
const secondNote = selectedNotes[1]
|
||||
const secondTitle = secondNote.title
|
||||
const secondText =
|
||||
secondNote.noteType === NoteType.Super && convertSuperToMarkdown
|
||||
? new HeadlessSuperConverter().convertString(secondNote.text, 'md')
|
||||
? new HeadlessSuperConverter().convertSuperStringToOtherFormat(secondNote.text, 'md')
|
||||
: secondNote.text
|
||||
|
||||
const titleDiff = fastdiff(firstTitle, secondTitle, undefined, true)
|
||||
|
||||
@@ -67,7 +67,7 @@ const AddTagOption: FunctionComponent<Props> = ({
|
||||
<Popover
|
||||
title="Add tag"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
side="right"
|
||||
align="start"
|
||||
|
||||
@@ -52,7 +52,7 @@ const ChangeEditorOption: FunctionComponent<ChangeEditorOptionProps> = ({ applic
|
||||
<Popover
|
||||
title="Change note type"
|
||||
align="start"
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
className="pt-2 md:pt-0"
|
||||
open={isOpen}
|
||||
side="right"
|
||||
|
||||
@@ -50,7 +50,7 @@ const ListedActionsOption: FunctionComponent<Props> = ({ application, note, icon
|
||||
<Popover
|
||||
title="Listed"
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
side="right"
|
||||
align="end"
|
||||
|
||||
@@ -35,7 +35,7 @@ const NotesOptionsPanel = ({ notesController, onClickPreprocessing }: Props) =>
|
||||
title="Note options"
|
||||
disableClickOutside={disableClickOutside}
|
||||
togglePopover={toggleMenu}
|
||||
anchorElement={buttonRef.current}
|
||||
anchorElement={buttonRef}
|
||||
open={isOpen}
|
||||
className="select-none pt-2"
|
||||
>
|
||||
|
||||
@@ -63,13 +63,19 @@ const getStylesFromRect = (options: {
|
||||
side: PopoverSide
|
||||
align: PopoverAlignment
|
||||
disableMobileFullscreenTakeover?: boolean
|
||||
disableApplyingMobileWidth?: boolean
|
||||
maxHeight?: number | 'none'
|
||||
offset?: number
|
||||
}): PopoverCSSProperties => {
|
||||
const { rect, disableMobileFullscreenTakeover = false, maxHeight = 'none' } = options
|
||||
const {
|
||||
rect,
|
||||
disableMobileFullscreenTakeover = false,
|
||||
disableApplyingMobileWidth = false,
|
||||
maxHeight = 'none',
|
||||
} = options
|
||||
|
||||
const canApplyMaxHeight = maxHeight !== 'none' && (!isMobileScreen() || disableMobileFullscreenTakeover)
|
||||
const shouldApplyMobileWidth = isMobileScreen() && disableMobileFullscreenTakeover
|
||||
const shouldApplyMobileWidth = isMobileScreen() && disableMobileFullscreenTakeover && !disableApplyingMobileWidth
|
||||
const marginForMobile = percentOf(10, window.innerWidth)
|
||||
|
||||
return {
|
||||
@@ -96,6 +102,7 @@ type Options = {
|
||||
popoverRect?: DOMRect
|
||||
side: PopoverSide
|
||||
disableMobileFullscreenTakeover?: boolean
|
||||
disableApplyingMobileWidth?: boolean
|
||||
maxHeightFunction?: (calculatedMaxHeight: number) => number | 'none'
|
||||
offset?: number
|
||||
}
|
||||
@@ -107,6 +114,7 @@ export const getPositionedPopoverStyles = ({
|
||||
popoverRect,
|
||||
side,
|
||||
disableMobileFullscreenTakeover,
|
||||
disableApplyingMobileWidth,
|
||||
maxHeightFunction,
|
||||
offset,
|
||||
}: Options): PopoverCSSProperties | null => {
|
||||
@@ -159,6 +167,7 @@ export const getPositionedPopoverStyles = ({
|
||||
side: sideWithLessOverflows,
|
||||
align: finalAlignment,
|
||||
disableMobileFullscreenTakeover,
|
||||
disableApplyingMobileWidth,
|
||||
maxHeight,
|
||||
offset,
|
||||
})
|
||||
|
||||
@@ -52,6 +52,7 @@ const MobilePopoverContent = ({
|
||||
<div
|
||||
ref={mergeRefs([setPopoverElement, addCloseMethod])}
|
||||
className="fixed left-0 top-0 z-modal flex h-full w-full flex-col bg-default pb-safe-bottom pt-safe-top"
|
||||
id={'popover/' + id}
|
||||
data-popover={id}
|
||||
data-mobile-popover
|
||||
>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
import { useAndroidBackHandler } from '@/NativeMobileWeb/useAndroidBackHandler'
|
||||
import { UuidGenerator } from '@standardnotes/snjs'
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { createContext, useCallback, useContext, useEffect, useId, useMemo, useState } from 'react'
|
||||
import MobilePopoverContent from './MobilePopoverContent'
|
||||
import PositionedPopoverContent from './PositionedPopoverContent'
|
||||
import { PopoverProps } from './Types'
|
||||
@@ -62,11 +61,11 @@ const PositionedPopoverContentWithAnimation = (
|
||||
}
|
||||
|
||||
const Popover = (props: PopoverProps) => {
|
||||
const popoverId = useRef(UuidGenerator.GenerateUuid())
|
||||
const popoverId = useId()
|
||||
|
||||
const addAndroidBackHandler = useAndroidBackHandler()
|
||||
|
||||
useRegisterPopoverToParent(popoverId.current)
|
||||
useRegisterPopoverToParent(popoverId)
|
||||
|
||||
const [childPopovers, setChildPopovers] = useState<Set<string>>(new Set())
|
||||
|
||||
@@ -106,6 +105,27 @@ const Popover = (props: PopoverProps) => {
|
||||
}
|
||||
}, [addAndroidBackHandler, props, props.open])
|
||||
|
||||
useEffect(() => {
|
||||
const anchorElement =
|
||||
props.anchorElement && 'current' in props.anchorElement ? props.anchorElement.current : props.anchorElement
|
||||
|
||||
if (anchorElement) {
|
||||
anchorElement.setAttribute('aria-haspopup', 'true')
|
||||
if (props.open) {
|
||||
anchorElement.setAttribute('aria-expanded', 'true')
|
||||
} else {
|
||||
anchorElement.removeAttribute('aria-expanded')
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (anchorElement) {
|
||||
anchorElement.removeAttribute('aria-haspopup')
|
||||
anchorElement.removeAttribute('aria-expanded')
|
||||
}
|
||||
}
|
||||
}, [props.anchorElement, props.open])
|
||||
|
||||
const isMobileScreen = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||
|
||||
if (isMobileScreen && !props.disableMobileFullscreenTakeover) {
|
||||
@@ -117,7 +137,7 @@ const Popover = (props: PopoverProps) => {
|
||||
}}
|
||||
title={props.title}
|
||||
className={props.className}
|
||||
id={popoverId.current}
|
||||
id={popoverId}
|
||||
>
|
||||
{props.children}
|
||||
</MobilePopoverContent>
|
||||
@@ -126,7 +146,7 @@ const Popover = (props: PopoverProps) => {
|
||||
|
||||
return (
|
||||
<PopoverContext.Provider value={contextValue}>
|
||||
<PositionedPopoverContentWithAnimation {...props} childPopovers={childPopovers} id={popoverId.current} />
|
||||
<PositionedPopoverContentWithAnimation {...props} childPopovers={childPopovers} id={popoverId} />
|
||||
</PopoverContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useDocumentRect } from '@/Hooks/useDocumentRect'
|
||||
import { useAutoElementRect } from '@/Hooks/useElementRect'
|
||||
import { classNames } from '@standardnotes/utils'
|
||||
import { CSSProperties, useCallback, useLayoutEffect, useState } from 'react'
|
||||
import { CSSProperties, useCallback, useLayoutEffect, useRef, useState } from 'react'
|
||||
import Portal from '../Portal/Portal'
|
||||
import { PopoverCSSProperties, getPositionedPopoverStyles } from './GetPositionedPopoverStyles'
|
||||
import { PopoverContentProps } from './Types'
|
||||
@@ -35,7 +35,8 @@ const PositionedPopoverContent = ({
|
||||
}: PopoverContentProps) => {
|
||||
const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)
|
||||
const popoverRect = useAutoElementRect(popoverElement)
|
||||
const anchorElementRect = useAutoElementRect(anchorElement, {
|
||||
const resolvedAnchorElement = anchorElement && 'current' in anchorElement ? anchorElement.current : anchorElement
|
||||
const anchorElementRect = useAutoElementRect(resolvedAnchorElement, {
|
||||
updateOnWindowResize: true,
|
||||
})
|
||||
const anchorPointRect = DOMRect.fromRect({
|
||||
@@ -75,7 +76,7 @@ const PositionedPopoverContent = ({
|
||||
|
||||
usePopoverCloseOnClickOutside({
|
||||
popoverElement,
|
||||
anchorElement,
|
||||
anchorElement: resolvedAnchorElement,
|
||||
togglePopover,
|
||||
childPopovers,
|
||||
hideOnClickInModal,
|
||||
@@ -84,17 +85,13 @@ const PositionedPopoverContent = ({
|
||||
|
||||
useDisableBodyScrollOnMobile()
|
||||
|
||||
const correctInitialScrollForOverflowedContent = useCallback(() => {
|
||||
if (popoverElement) {
|
||||
setTimeout(() => {
|
||||
popoverElement.scrollTop = 0
|
||||
}, 10)
|
||||
const canCorrectInitialScroll = useRef(true)
|
||||
const correctInitialScrollForOverflowedContent = useCallback((element: HTMLElement | null) => {
|
||||
if (element && element.scrollTop > 0 && canCorrectInitialScroll.current) {
|
||||
element.scrollTop = 0
|
||||
canCorrectInitialScroll.current = false
|
||||
}
|
||||
}, [popoverElement])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
correctInitialScrollForOverflowedContent()
|
||||
}, [popoverElement, correctInitialScrollForOverflowedContent])
|
||||
}, [])
|
||||
|
||||
const addCloseMethod = useCallback(
|
||||
(element: HTMLDivElement | null) => {
|
||||
@@ -122,13 +119,14 @@ const PositionedPopoverContent = ({
|
||||
} as CSSProperties
|
||||
}
|
||||
ref={mergeRefs([setPopoverElement, addCloseMethod])}
|
||||
id={'popover/' + id}
|
||||
data-popover={id}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === KeyboardKey.Escape) {
|
||||
event.stopPropagation()
|
||||
togglePopover?.()
|
||||
if (anchorElement) {
|
||||
anchorElement.focus()
|
||||
if (resolvedAnchorElement) {
|
||||
resolvedAnchorElement.focus()
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -148,7 +146,10 @@ const PositionedPopoverContent = ({
|
||||
styles ? 'scale-100 opacity-100' : 'scale-95 opacity-0',
|
||||
className,
|
||||
)}
|
||||
ref={setAnimationElement}
|
||||
ref={mergeRefs([correctInitialScrollForOverflowedContent, setAnimationElement])}
|
||||
onScroll={() => {
|
||||
canCorrectInitialScroll.current = false
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { ReactNode, RefObject } from 'react'
|
||||
|
||||
export type PopoverState = 'closed' | 'positioning' | 'open'
|
||||
|
||||
@@ -20,8 +20,10 @@ type Point = {
|
||||
y: number
|
||||
}
|
||||
|
||||
type AnchorElementOrRef = RefObject<HTMLElement | null> | HTMLElement | null
|
||||
|
||||
type PopoverAnchorElementProps = {
|
||||
anchorElement: HTMLElement | null
|
||||
anchorElement: AnchorElementOrRef
|
||||
anchorPoint?: never
|
||||
}
|
||||
|
||||
@@ -49,7 +51,7 @@ type CommonPopoverProps = {
|
||||
}
|
||||
|
||||
export type PopoverContentProps = CommonPopoverProps & {
|
||||
anchorElement?: HTMLElement | null
|
||||
anchorElement?: AnchorElementOrRef
|
||||
anchorPoint?: Point
|
||||
childPopovers: Set<string>
|
||||
togglePopover?: () => void
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@ export const usePopoverCloseOnClickOutside = ({
|
||||
const closestPopoverId = target.closest('[data-popover]')?.getAttribute('data-popover')
|
||||
const isDescendantOfChildPopover = closestPopoverId && childPopovers.has(closestPopoverId)
|
||||
const isPopoverInModal = popoverElement?.closest('[data-dialog], .sk-modal')
|
||||
const isDescendantOfModal = isPopoverInModal ? false : !!target.closest('[data-dialog], .sk-modal')
|
||||
const isDescendantOfModal = isPopoverInModal
|
||||
? false
|
||||
: !!target.closest('[data-dialog], [data-backdrop], .sk-modal')
|
||||
const isDescendantOfDesktopTitlebar = !!target.closest('#desktop-title-bar')
|
||||
|
||||
if (
|
||||
|
||||
+2
-1
@@ -7,6 +7,7 @@ import { PackageProvider } from '@/Components/Preferences/Panes/General/Advanced
|
||||
import AccordionItem from '@/Components/Shared/AccordionItem'
|
||||
import PreferencesGroup from '../../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../../PreferencesComponents/PreferencesSegment'
|
||||
import { Platform } from '@standardnotes/snjs'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -20,7 +21,7 @@ const Advanced: FunctionComponent<Props> = ({ application, extensionsLatestVersi
|
||||
<AccordionItem title={'Advanced options'}>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="flex max-w-full flex-grow flex-col">
|
||||
<OfflineSubscription application={application} />
|
||||
{application.platform !== Platform.Ios && <OfflineSubscription application={application} />}
|
||||
<PackagesPreferencesSection
|
||||
className={'mt-3'}
|
||||
application={application}
|
||||
|
||||
+3
-3
@@ -96,7 +96,7 @@ const EditSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="text-sm font-semibold">Title:</div>
|
||||
<input
|
||||
className="rounded border border-border bg-default px-2 py-1"
|
||||
className="rounded border border-border bg-default md:translucent-ui:bg-transparent px-2 py-1"
|
||||
value={title}
|
||||
onChange={(event) => {
|
||||
setTitle(event.target.value)
|
||||
@@ -117,7 +117,7 @@ const EditSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<Popover
|
||||
title="Choose icon"
|
||||
open={shouldShowIconPicker}
|
||||
anchorElement={iconPickerButtonRef.current}
|
||||
anchorElement={iconPickerButtonRef}
|
||||
togglePopover={toggleIconPicker}
|
||||
align="start"
|
||||
overrideZIndex="z-modal"
|
||||
@@ -139,7 +139,7 @@ const EditSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<div className="text-sm font-semibold">Predicate:</div>
|
||||
<div className="flex flex-grow flex-col overflow-hidden rounded-md border border-border">
|
||||
<textarea
|
||||
className="h-full min-h-[10rem] w-full flex-grow resize-none bg-default px-2.5 py-1.5 font-mono text-sm"
|
||||
className="h-full min-h-[10rem] w-full flex-grow resize-none bg-default px-2.5 py-1.5 font-mono text-sm md:translucent-ui:bg-transparent"
|
||||
value={predicateJson}
|
||||
onChange={(event) => {
|
||||
setPredicateJson(event.target.value)
|
||||
|
||||
+1
-1
@@ -244,7 +244,7 @@ const EditVaultModal: FunctionComponent<Props> = ({ onCloseDialog, existingVault
|
||||
<Popover
|
||||
title="Choose icon"
|
||||
open={shouldShowIconPicker}
|
||||
anchorElement={iconPickerButtonRef.current}
|
||||
anchorElement={iconPickerButtonRef}
|
||||
togglePopover={toggleIconPicker}
|
||||
align="start"
|
||||
overrideZIndex="z-modal"
|
||||
|
||||
@@ -50,7 +50,7 @@ const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperProps> = (
|
||||
animate="mobile"
|
||||
animationVariant="horizontal"
|
||||
close={application.preferencesController.closePreferences}
|
||||
className="md:h-full md:!max-h-full md:!w-full"
|
||||
className="md:!border-0 md:h-full md:!max-h-full md:!w-full"
|
||||
>
|
||||
<PreferencesView
|
||||
closePreferences={application.preferencesController.closePreferences}
|
||||
|
||||
+3
-9
@@ -1,17 +1,16 @@
|
||||
import AlertDialog from '../AlertDialog/AlertDialog'
|
||||
import { FunctionComponent, useRef } from 'react'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { PremiumFeatureModalType } from './PremiumFeatureModalType'
|
||||
import { FeatureName } from '@/Controllers/FeatureName'
|
||||
import { SuccessPrompt } from './Subviews/SuccessPrompt'
|
||||
import { UpgradePrompt } from './Subviews/UpgradePrompt'
|
||||
import Modal from '../Modal/Modal'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
featureName?: FeatureName | string
|
||||
hasSubscription: boolean
|
||||
onClose: () => void
|
||||
showModal: boolean
|
||||
type: PremiumFeatureModalType
|
||||
}
|
||||
|
||||
@@ -20,17 +19,12 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
|
||||
featureName,
|
||||
hasSubscription,
|
||||
onClose,
|
||||
showModal,
|
||||
type = PremiumFeatureModalType.UpgradePrompt,
|
||||
}) => {
|
||||
const ctaButtonRef = useRef<HTMLButtonElement>(null)
|
||||
|
||||
if (!showModal) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<AlertDialog closeDialog={onClose} className="w-full max-w-[90vw] md:max-w-89">
|
||||
<Modal close={onClose} title="Upgrade" className="px-6 py-5" customHeader={<></>}>
|
||||
<div tabIndex={-1} className="sn-component">
|
||||
<div tabIndex={0}>
|
||||
{type === PremiumFeatureModalType.UpgradePrompt && (
|
||||
@@ -46,7 +40,7 @@ const PremiumFeaturesModal: FunctionComponent<Props> = ({
|
||||
{type === PremiumFeatureModalType.UpgradeSuccess && <SuccessPrompt ctaRef={ctaButtonRef} onClose={onClose} />}
|
||||
</div>
|
||||
</div>
|
||||
</AlertDialog>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ export const UpgradePrompt = ({
|
||||
onClose: () => void
|
||||
}) => {
|
||||
const handleClick = useCallback(() => {
|
||||
if (hasSubscription) {
|
||||
if (hasSubscription && !application.isNativeIOS()) {
|
||||
void application.openSubscriptionDashboard.execute()
|
||||
} else {
|
||||
void application.openPurchaseFlow()
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ const HistoryModalDialogContent = ({ dismissModal, note }: RevisionHistoryModalC
|
||||
<Popover
|
||||
title="Advanced"
|
||||
open={showTabMenu}
|
||||
anchorElement={tabOptionRef.current}
|
||||
anchorElement={tabOptionRef}
|
||||
disableMobileFullscreenTakeover={true}
|
||||
togglePopover={toggleTabMenu}
|
||||
align="start"
|
||||
|
||||
@@ -168,7 +168,7 @@ const AddSmartViewModal = ({ controller, platform }: Props) => {
|
||||
<Popover
|
||||
title="Choose icon"
|
||||
open={shouldShowIconPicker}
|
||||
anchorElement={iconPickerButtonRef.current}
|
||||
anchorElement={iconPickerButtonRef}
|
||||
togglePopover={toggleIconPicker}
|
||||
align="start"
|
||||
overrideZIndex="z-modal"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { classNames } from '@standardnotes/snjs'
|
||||
import { ReactNode, useState } from 'react'
|
||||
import { ReactNode, useState, useRef, useEffect } from 'react'
|
||||
import { Tooltip, TooltipAnchor, TooltipOptions, useTooltipStore } from '@ariakit/react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
import { getPositionedPopoverStyles } from '../Popover/GetPositionedPopoverStyles'
|
||||
import { getAdjustedStylesForNonPortalPopover } from '../Popover/Utils/getAdjustedStylesForNonPortal'
|
||||
import { useLongPressEvent } from '@/Hooks/useLongPress'
|
||||
|
||||
const StyledTooltip = ({
|
||||
children,
|
||||
@@ -24,13 +25,43 @@ const StyledTooltip = ({
|
||||
} & Partial<TooltipOptions>) => {
|
||||
const [forceOpen, setForceOpen] = useState<boolean | undefined>()
|
||||
|
||||
const isMobile = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||
const tooltip = useTooltipStore({
|
||||
timeout: 500,
|
||||
timeout: isMobile && showOnMobile ? 100 : 500,
|
||||
hideTimeout: 0,
|
||||
skipTimeout: 0,
|
||||
open: forceOpen,
|
||||
animated: true,
|
||||
})
|
||||
const isMobile = useMediaQuery(MutuallyExclusiveMediaQueryBreakpoints.sm)
|
||||
|
||||
const anchorRef = useRef<HTMLElement>(null)
|
||||
const { attachEvents: attachLongPressEvents, cleanupEvents: cleanupLongPressEvents } = useLongPressEvent(
|
||||
anchorRef,
|
||||
() => {
|
||||
tooltip.show()
|
||||
setTimeout(() => {
|
||||
tooltip.hide()
|
||||
}, 2000)
|
||||
},
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isMobile || !showOnMobile) {
|
||||
return
|
||||
}
|
||||
|
||||
attachLongPressEvents()
|
||||
|
||||
return () => {
|
||||
cleanupLongPressEvents()
|
||||
}
|
||||
}, [attachLongPressEvents, cleanupLongPressEvents, isMobile, showOnMobile])
|
||||
|
||||
const clickProps = isMobile
|
||||
? {}
|
||||
: {
|
||||
onClick: () => setForceOpen(false),
|
||||
}
|
||||
|
||||
if (isMobile && !showOnMobile) {
|
||||
return <>{children}</>
|
||||
@@ -39,7 +70,8 @@ const StyledTooltip = ({
|
||||
return (
|
||||
<>
|
||||
<TooltipAnchor
|
||||
onClick={() => setForceOpen(false)}
|
||||
ref={anchorRef}
|
||||
{...clickProps}
|
||||
onBlur={() => setForceOpen(undefined)}
|
||||
store={tooltip}
|
||||
as={Slot}
|
||||
@@ -53,6 +85,8 @@ const StyledTooltip = ({
|
||||
store={tooltip}
|
||||
className={classNames(
|
||||
'z-tooltip max-w-max rounded border border-border translucent-ui:border-[--popover-border-color] bg-contrast translucent-ui:bg-[--popover-background-color] [backdrop-filter:var(--popover-backdrop-filter)] px-3 py-1.5 text-sm text-foreground shadow',
|
||||
'opacity-60 [&[data-enter]]:opacity-100 [&[data-leave]]:opacity-60 transition-opacity duration-75',
|
||||
'focus-visible:shadow-none focus-visible:outline-none',
|
||||
className,
|
||||
)}
|
||||
updatePosition={() => {
|
||||
@@ -79,6 +113,7 @@ const StyledTooltip = ({
|
||||
popoverRect,
|
||||
documentRect,
|
||||
disableMobileFullscreenTakeover: true,
|
||||
disableApplyingMobileWidth: true,
|
||||
offset: props.gutter ? props.gutter : 6,
|
||||
})
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import AutoEmbedPlugin from './Plugins/AutoEmbedPlugin'
|
||||
import CollapsiblePlugin from './Plugins/CollapsiblePlugin'
|
||||
import DraggableBlockPlugin from './Plugins/DraggableBlockPlugin'
|
||||
import CodeHighlightPlugin from './Plugins/CodeHighlightPlugin'
|
||||
import FloatingTextFormatToolbarPlugin from './Plugins/FloatingTextFormatToolbarPlugin'
|
||||
import FloatingTextFormatToolbarPlugin from './Plugins/ToolbarPlugins/FloatingTextFormatToolbarPlugin'
|
||||
import { TabIndentationPlugin } from './Plugins/TabIndentationPlugin'
|
||||
import { handleEditorChange } from './Utils'
|
||||
import { SuperEditorContentId } from './Constants'
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { LexicalEditor } from 'lexical'
|
||||
import { INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list'
|
||||
|
||||
export function GetBulletedListBlock(editor: LexicalEditor) {
|
||||
export function GetBulletedListBlock(editor: LexicalEditor, isActive = false) {
|
||||
return {
|
||||
name: 'Bulleted List',
|
||||
iconName: 'list-bulleted',
|
||||
keywords: ['bulleted list', 'unordered list', 'ul'],
|
||||
onSelect: () => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined),
|
||||
active: isActive,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { LexicalEditor } from 'lexical'
|
||||
import { INSERT_ORDERED_LIST_COMMAND } from '@lexical/list'
|
||||
|
||||
export function GetNumberedListBlock(editor: LexicalEditor) {
|
||||
export function GetNumberedListBlock(editor: LexicalEditor, isActive = false) {
|
||||
return {
|
||||
name: 'Numbered List',
|
||||
iconName: 'list-numbered',
|
||||
keywords: ['numbered list', 'ordered list', 'ol'],
|
||||
onSelect: () => editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined),
|
||||
active: isActive,
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user