Compare commits

...
Author SHA1 Message Date
StandardNotes CI 4b6662d62d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2022-10-05 20:52:08 +00:00
StandardNotes CI ac0ad49af0 chore(release): components 2022-10-05 20:51:54 +00:00
Aman Harwara 09b994f8f9 feat: add free dark mode (#1748) 2022-10-06 01:49:35 +05:30
Mo 6c26b96cdc fix(mobile): passcode timing options (#1744) 2022-10-05 10:08:54 -05:00
StandardNotes CI a4de9a05a9 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-10-05 13:48:42 +00:00
Mo 6bd5534f74 fix: prevent overflow bouncing on desktop and mobile (#1743)
* fix: prevent overflow bouncing on desktop and mobile

* fix: add black bg to webview for debugging purposes
2022-10-05 08:19:55 -05:00
Robbe Van Herck de0f91c9e3 fix(docs): Change order of sed commands (#1742)
As it was before, the value "secret" in "secret_key" and "jegacy_jwt_secret" would be replaced by the key generated for "secret". This reduced the security of the keys as all three keys would be almost the same. By moving the command for secret to the bottom, this problem no longer occurs.
2022-10-05 08:17:35 -05:00
StandardNotes CI 7fb418472c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-10-05 13:08:34 +00:00
Aman Harwara 376810e657 feat: add file info panel button to file view (#1741) 2022-10-05 18:08:34 +05:30
71 changed files with 534 additions and 208 deletions
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/api
## [1.9.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/api
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.9.1",
"version": "1.9.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.7.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/components-meta
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -70,9 +70,9 @@
"binary": "b621bfd81829a205f2f02e85d446e277ad20e367b92676ec20b3ee59b1bfab3f"
},
"org.standardnotes.markdown-visual-editor": {
"version": "1.1.2",
"base64": "2645d31c51fa6a198c14a32737ee4045dcbbecb8bdaa1432ca4686cab78834d2",
"binary": "c4479f8768f5f6cda41850212a8e03927990adfa33ebd36e29ee6de2335e8e46"
"version": "1.1.3",
"base64": "8bb35d66b0ef2bee2243dbdf514c0bf50ef706c034395cb9d50119f017fef9aa",
"binary": "1738193ab2a57cf280c29c9ca1e4caf49179009c7382048577d2b34eaf96d5e9"
},
"org.standardnotes.simple-task-editor": {
"version": "1.4.4",
@@ -80,9 +80,9 @@
"binary": "9df983a144b9686f4f58b03bf78bf1f84f53aea60251621a75586722bf576475"
},
"org.standardnotes.token-vault": {
"version": "2.2.4",
"base64": "ac07bd989bfb1100aeaacf6687b492b4aac754645da5a132ecd879dc64786522",
"binary": "8f74bacd0dd3a0a6e04bcce9c54694bb2f429b470a3023e96e0a750a271184ae"
"version": "2.2.5",
"base64": "ca103f730737d3a3046001666b626139692c08ab4dd5748b0290fdcb1b1eb04a",
"binary": "52f419cd60da00a2cad13fd357b50993c7694160fcca1c1bdf1859e3bdca3a2b"
},
"org.standardnotes.standard-sheets": {
"version": "1.5.1",
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.15",
"version": "2.7.16",
"private": true,
"author": "Standard Notes.",
"main": "dist",
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/markdown-visual
## [1.1.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-07-13)
### Bug Fixes
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/markdown-visual",
"version": "1.1.2",
"version": "1.1.3",
"author": "Johnny Almonte <[email protected]>",
"description": "A lightweight WYSIWYG markdown editor for Standard Notes, derived from Milkdown.",
"keywords": [
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/authenticator
## [2.2.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-22)
### Bug Fixes
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/authenticator",
"version": "2.2.4",
"version": "2.2.5",
"main": "dist/dist.js",
"author": "Standard Notes",
"private": true,
+12
View File
@@ -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.
## [3.23.192](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.191](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.190](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.189](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.189",
"version": "3.23.192",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* **docs:** Change order of sed commands ([#1742](https://github.com/standardnotes/app/issues/1742)) ([de0f91c](https://github.com/standardnotes/app/commit/de0f91c9e38883613f942ba85d9f3d0bc360dba3))
# [0.2.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-17)
### Features
+1 -1
View File
@@ -166,10 +166,10 @@ Due to mounted volumes, we recommend running the setup as a root user. If you wi
```shell
sed -i "s/auth_jwt_secret/$(openssl rand -hex 32)/g" .env
sed -i "s/secret/$(openssl rand -hex 32)/g" docker/auth.env
sed -i "s/legacy_jwt_secret/$(openssl rand -hex 32)/g" docker/auth.env
sed -i "s/secret_key/$(openssl rand -hex 32)/g" docker/auth.env
sed -i "s/server_key/$(openssl rand -hex 32)/g" docker/auth.env
sed -i "s/secret/$(openssl rand -hex 32)/g" docker/auth.env
```
**Note:** If you are running `sed` on macOS or BSD, change instances of `sed -i` to `sed -i ''`.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/docs",
"version": "0.2.0",
"version": "0.2.1",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.15.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/encryption
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.15.10",
"version": "1.15.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.23.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/filepicker
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.23.10",
"version": "1.23.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.10.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/files
## [1.10.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/files
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.10.10",
"version": "1.10.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.39.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* **mobile:** passcode timing options ([#1744](https://github.com/standardnotes/app/issues/1744)) ([6c26b96](https://github.com/standardnotes/app/commit/6c26b96cdce0d69a4a459104709880850a401a92))
## [3.39.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* prevent overflow bouncing on desktop and mobile ([#1743](https://github.com/standardnotes/app/issues/1743)) ([6bd5534](https://github.com/standardnotes/app/commit/6bd5534f749a35b5ddc35cb09115358ce9ee4115))
## [3.39.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/mobile
## [3.39.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/mobile
+2 -2
View File
@@ -419,7 +419,7 @@ PODS:
- React-RCTImage
- RNSearchBar (3.5.1):
- React-Core
- RNShare (7.6.4):
- RNShare (7.9.0):
- React-Core
- RNStoreReview (0.2.1):
- React-Core
@@ -744,7 +744,7 @@ SPEC CHECKSUMS:
RNReanimated: b5b17149593e7c05e4ec5c0efea1f21e05829510
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19
RNSearchBar: 5ed8e13ba8a6c701fbd2afdfe4164493d24b2aee
RNShare: 4406f61af043027b695c3a0b8f39e2c2bdacde12
RNShare: be91a5c149585affb02c25b351bd07ba927c7006
RNStoreReview: e05edbbf426563070524cec384ac0b8df69be801
RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.39.6",
"version": "3.39.9",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
@@ -9,7 +9,7 @@
"android-prod-debug": "react-native run-android --variant prodDebug",
"android-prod-release": "yarn run android:bundle && react-native run-android --variant prodRelease",
"android:bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/build/intermediates/res/merged/release/",
"build": "yarn web:bundle && yarn install:pods && yarn android:bundle",
"build": "yarn bundle:web && yarn install:pods && yarn android:bundle",
"clear-cache": "watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-*",
"format:fix": "yarn format --write",
"format": "prettier ./src",
@@ -22,7 +22,7 @@
"start": "react-native start",
"tsc": "tsc --noEmit",
"upgrade:snjs": "ncu -u '@standardnotes/*'",
"web:bundle": "mkdir -p html/Web.bundle/src/web-src/ && cp -r ../web/dist/. html/Web.bundle/src/web-src/ && mkdir -p html/Web.bundle/src/components/assets && cp -r ../components/dist/assets/. html/Web.bundle/src/components/assets/"
"bundle:web": "mkdir -p html/Web.bundle/src/web-src/ && cp -r ../web/dist/. html/Web.bundle/src/web-src/ && mkdir -p html/Web.bundle/src/components/assets && cp -r ../components/dist/assets/. html/Web.bundle/src/components/assets/"
},
"installConfig": {
"hoistingLimits": "workspaces"
+5 -5
View File
@@ -483,7 +483,7 @@ export class ApplicationState extends ApplicationService {
return
}
const hasBiometrics = this.application.hasBiometrics()
const hasBiometrics = this.application.protections.hasBiometricsEnabled()
const hasPasscode = this.application.hasPasscode()
const passcodeLockImmediately = hasPasscode && this.passcodeTiming === MobileUnlockTiming.Immediately
const biometricsLockImmediately =
@@ -571,19 +571,19 @@ export class ApplicationState extends ApplicationService {
}
private async getScreenshotPrivacyEnabled(): Promise<boolean> {
return this.application.getMobileScreenshotPrivacyEnabled()
return this.application.protections.getMobileScreenshotPrivacyEnabled()
}
private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
return this.application.getMobilePasscodeTiming()
return this.application.protections.getMobilePasscodeTiming()
}
private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
return this.application.getMobileBiometricsTiming()
return this.application.protections.getMobileBiometricsTiming()
}
public async setScreenshotPrivacyEnabled(enabled: boolean) {
await this.application.setMobileScreenshotPrivacyEnabled(enabled)
await this.application.protections.setMobileScreenshotPrivacyEnabled(enabled)
this.screenshotPrivacyEnabled = enabled
await (this.application.deviceInterface as MobileDevice).setAndroidScreenshotPrivacy(enabled)
}
@@ -195,13 +195,12 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
webViewRef.current?.postMessage(JSON.stringify({ messageId, returnValue, messageType: 'reply' }))
}
/* eslint-disable @typescript-eslint/no-empty-function */
return (
<WebView
ref={webViewRef}
source={{ uri: sourceUri }}
style={{ backgroundColor: 'black' }}
originWhitelist={['*']}
onLoad={() => {}}
onError={(err) => console.error('An error has occurred', err)}
onHttpError={() => console.error('An HTTP error occurred')}
onMessage={onMessage}
@@ -211,5 +210,4 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
bounces={false}
/>
)
/* eslint-enable @typescript-eslint/no-empty-function */
}
@@ -197,7 +197,7 @@ export const Authenticate = ({
state: AuthenticationValueStateType.Pending,
})
if (await application?.getMobileScreenshotPrivacyEnabled()) {
if (application?.protections.getMobileScreenshotPrivacyEnabled()) {
hide()
}
@@ -31,21 +31,23 @@ export const SecuritySection = (props: Props) => {
const [hasBiometrics, setHasBiometrics] = useState(false)
const [supportsBiometrics, setSupportsBiometrics] = useState(false)
const [biometricsTimingOptions, setBiometricsTimingOptions] = useState(() =>
application!.getBiometricsTimingOptions(),
application!.protections.getMobileBiometricsTimingOptions(),
)
const [passcodeTimingOptions, setPasscodeTimingOptions] = useState(() =>
application!.protections.getMobilePasscodeTimingOptions(),
)
const [passcodeTimingOptions, setPasscodeTimingOptions] = useState(() => application!.getPasscodeTimingOptions())
useEffect(() => {
let mounted = true
const getHasScreenshotPrivacy = async () => {
const hasScreenshotPrivacyEnabled = application?.getMobileScreenshotPrivacyEnabled()
const hasScreenshotPrivacyEnabled = application?.protections.getMobileScreenshotPrivacyEnabled()
if (mounted) {
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}
}
void getHasScreenshotPrivacy()
const getHasBiometrics = async () => {
const appHasBiometrics = application!.hasBiometrics()
const appHasBiometrics = application!.protections.hasBiometricsEnabled()
if (mounted) {
setHasBiometrics(appHasBiometrics)
}
@@ -68,7 +70,7 @@ export const SecuritySection = (props: Props) => {
useFocusEffect(
useCallback(() => {
if (props.hasPasscode) {
setPasscodeTimingOptions(() => application!.getPasscodeTimingOptions())
setPasscodeTimingOptions(() => application!.protections.getMobilePasscodeTimingOptions())
}
}, [application, props.hasPasscode]),
)
@@ -126,12 +128,12 @@ export const SecuritySection = (props: Props) => {
const setBiometricsTiming = async (timing: MobileUnlockTiming) => {
await application?.getAppState().setBiometricsTiming(timing)
setBiometricsTimingOptions(() => application!.getBiometricsTimingOptions())
setBiometricsTimingOptions(() => application!.protections.getMobileBiometricsTimingOptions())
}
const setPasscodeTiming = async (timing: MobileUnlockTiming) => {
await application?.getAppState().setPasscodeTiming(timing)
setPasscodeTimingOptions(() => application!.getPasscodeTimingOptions())
setPasscodeTimingOptions(() => application!.protections.getMobilePasscodeTimingOptions())
}
const onScreenshotPrivacyPress = async () => {
@@ -153,14 +155,14 @@ export const SecuritySection = (props: Props) => {
void disableAuthentication('biometrics')
} else {
setHasBiometrics(true)
await application?.enableBiometrics()
await application?.protections.enableBiometrics()
await setBiometricsTiming(MobileUnlockTiming.OnQuit)
props.updateProtectionsAvailable()
}
}
const disableBiometrics = useCallback(async () => {
if (await application?.disableBiometrics()) {
if (await application?.protections.disableBiometrics()) {
setHasBiometrics(false)
props.updateProtectionsAvailable()
}
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.23.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Features
* add free dark mode ([#1748](https://github.com/standardnotes/app/issues/1748)) ([09b994f](https://github.com/standardnotes/app/commit/09b994f8f938ae0536f42742f7a221df536c4c4a))
## [1.22.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/models
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.22.1",
"version": "1.23.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -37,6 +37,7 @@ export enum PrefKey {
NewNoteTitleFormat = 'newNoteTitleFormat',
CustomNoteTitleFormat = 'customNoteTitleFormat',
UpdateSavingStatusIndicator = 'updateSavingStatusIndicator',
DarkMode = 'darkMode',
}
export enum NewNoteTitleFormat {
@@ -82,8 +83,8 @@ export type PrefValue = {
[PrefKey.NotesHideTags]: boolean
[PrefKey.NotesHideEditorIcon]: boolean
[PrefKey.UseSystemColorScheme]: boolean
[PrefKey.AutoLightThemeIdentifier]: FeatureIdentifier | 'Default'
[PrefKey.AutoDarkThemeIdentifier]: FeatureIdentifier | 'Default'
[PrefKey.AutoLightThemeIdentifier]: FeatureIdentifier | 'Default' | 'Dark'
[PrefKey.AutoDarkThemeIdentifier]: FeatureIdentifier | 'Default' | 'Dark'
[PrefKey.NoteAddToParentFolders]: boolean
[PrefKey.MobileSortNotesBy]: CollectionSortProperty
[PrefKey.MobileSortNotesReverse]: boolean
@@ -99,4 +100,5 @@ export type PrefValue = {
[PrefKey.EditorLineHeight]: EditorLineHeight
[PrefKey.EditorFontSize]: EditorFontSize
[PrefKey.UpdateSavingStatusIndicator]: boolean
[PrefKey.DarkMode]: boolean
}
+12
View File
@@ -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.
## [1.3.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.116](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.115](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.114](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.114",
"version": "1.3.117",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.24.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/services
## [1.24.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.24.2",
"version": "1.24.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.134.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* **mobile:** passcode timing options ([#1744](https://github.com/standardnotes/app/issues/1744)) ([6c26b96](https://github.com/standardnotes/app/commit/6c26b96cdce0d69a4a459104709880850a401a92))
## [2.134.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/snjs
@@ -45,7 +45,6 @@ import {
FileService,
SubscriptionClientInterface,
SubscriptionManager,
StorageValueModes,
} from '@standardnotes/services'
import { FilesClientInterface } from '@standardnotes/files'
import { ComputePrivateWorkspaceIdentifier } from '@standardnotes/encryption'
@@ -65,7 +64,6 @@ import { SNLog } from '../Log'
import { Challenge, ChallengeResponse } from '../Services'
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
import { ApplicationOptionsDefaults } from './Options/Defaults'
import { MobileUnlockTiming } from '@Lib/Services/Protection/MobileUnlockTiming'
/** How often to automatically sync, in milliseconds */
const DEFAULT_AUTO_SYNC_INTERVAL = 30_000
@@ -899,24 +897,6 @@ export class SNApplication
return this.launched
}
public hasBiometrics(): boolean {
return this.protectionService.hasBiometricsEnabled()
}
/**
* @returns whether the operation was successful or not
*/
public enableBiometrics(): boolean {
return this.protectionService.enableBiometrics()
}
/**
* @returns whether the operation was successful or not
*/
public disableBiometrics(): Promise<boolean> {
return this.protectionService.disableBiometrics()
}
public hasPasscode(): boolean {
return this.protocolService.hasPasscode()
}
@@ -936,38 +916,6 @@ export class SNApplication
return this.deinit(this.getDeinitMode(), DeinitSource.Lock)
}
setBiometricsTiming(timing: MobileUnlockTiming) {
return this.protectionService.setBiometricsTiming(timing)
}
getMobileScreenshotPrivacyEnabled(): boolean {
return this.protectionService.getMobileScreenshotPrivacyEnabled()
}
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.protectionService.setMobileScreenshotPrivacyEnabled(isEnabled)
}
getMobilePasscodeTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}
getMobileBiometricsTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}
getBiometricsTimingOptions() {
return this.protectionService.getBiometricsTimingOptions()
}
getPasscodeTimingOptions() {
return this.protectionService.getPasscodeTimingOptions()
}
isNativeMobileWeb() {
return this.environment === Environment.NativeMobileWeb
}
@@ -1,8 +1,19 @@
import { ChallengeReason } from '@standardnotes/services'
import { DecryptedItem } from '@standardnotes/models'
import { TimingDisplayOption, MobileUnlockTiming } from './MobileUnlockTiming'
export interface ProtectionsClientInterface {
authorizeProtectedActionForItems<T extends DecryptedItem>(files: T[], challengeReason: ChallengeReason): Promise<T[]>
authorizeItemAccess(item: DecryptedItem): Promise<boolean>
getMobileBiometricsTiming(): MobileUnlockTiming | undefined
getMobilePasscodeTiming(): MobileUnlockTiming | undefined
setMobileBiometricsTiming(timing: MobileUnlockTiming): void
setMobilePasscodeTiming(timing: MobileUnlockTiming): void
setMobileScreenshotPrivacyEnabled(isEnabled: boolean): void
getMobileScreenshotPrivacyEnabled(): boolean
getMobilePasscodeTimingOptions(): TimingDisplayOption[]
getMobileBiometricsTimingOptions(): TimingDisplayOption[]
hasBiometricsEnabled(): boolean
enableBiometrics(): boolean
disableBiometrics(): Promise<boolean>
}
@@ -2,3 +2,9 @@ export enum MobileUnlockTiming {
Immediately = 'immediately',
OnQuit = 'on-quit',
}
export type TimingDisplayOption = {
title: string
key: MobileUnlockTiming
selected: boolean
}
@@ -18,7 +18,7 @@ import {
} from '@standardnotes/services'
import { ProtectionsClientInterface } from './ClientInterface'
import { ContentType } from '@standardnotes/common'
import { MobileUnlockTiming } from './MobileUnlockTiming'
import { MobileUnlockTiming, TimingDisplayOption } from './MobileUnlockTiming'
export enum ProtectionEvent {
UnprotectedSessionBegan = 'UnprotectedSessionBegan',
@@ -64,8 +64,8 @@ export const ProtectionSessionDurations = [
*/
export class SNProtectionService extends AbstractService<ProtectionEvent> implements ProtectionsClientInterface {
private sessionExpiryTimeout = -1
private mobilePasscodeTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.Immediately
private mobileBiometricsTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.Immediately
private mobilePasscodeTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
private mobileBiometricsTiming: MobileUnlockTiming | undefined = MobileUnlockTiming.OnQuit
constructor(
private protocolService: EncryptionService,
@@ -87,8 +87,8 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
override handleApplicationStage(stage: ApplicationStage): Promise<void> {
if (stage === ApplicationStage.LoadedDatabase_12) {
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
this.mobilePasscodeTiming = this.getPasscodeTiming()
this.mobileBiometricsTiming = this.getBiometricsTiming()
this.mobilePasscodeTiming = this.getMobilePasscodeTiming()
this.mobileBiometricsTiming = this.getMobileBiometricsTiming()
}
return Promise.resolve()
}
@@ -229,7 +229,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
})
}
getPasscodeTimingOptions() {
getMobilePasscodeTimingOptions(): TimingDisplayOption[] {
return [
{
title: 'Immediately',
@@ -244,7 +244,7 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
]
}
getBiometricsTimingOptions() {
getMobileBiometricsTimingOptions(): TimingDisplayOption[] {
return [
{
title: 'Immediately',
@@ -259,25 +259,32 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
]
}
private getBiometricsTiming(): MobileUnlockTiming | undefined {
getMobileBiometricsTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobileBiometricsTiming,
StorageValueModes.Nonwrapped,
MobileUnlockTiming.OnQuit,
)
}
private getPasscodeTiming(): MobileUnlockTiming | undefined {
getMobilePasscodeTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobilePasscodeTiming,
StorageValueModes.Nonwrapped,
MobileUnlockTiming.OnQuit,
)
}
async setBiometricsTiming(timing: MobileUnlockTiming) {
setMobileBiometricsTiming(timing: MobileUnlockTiming): void {
this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.mobileBiometricsTiming = timing
}
setMobilePasscodeTiming(timing: MobileUnlockTiming): void {
this.storageService.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
this.mobilePasscodeTiming = timing
}
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.storageService.setValue(StorageKey.MobileScreenshotPrivacyEnabled, isEnabled, StorageValueModes.Default)
}
+1 -1
View File
@@ -62,7 +62,7 @@ describe('device authentication', function () {
const passcode = 'foobar'
const wrongPasscode = 'barfoo'
await application.addPasscode(passcode)
await application.protectionService.enableBiometrics()
await application.protections.enableBiometrics()
expect(await application.hasPasscode()).to.equal(true)
expect((await application.protectionService.createLaunchChallenge()).prompts.length).to.equal(2)
expect(application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.WrapperOnly)
+4 -4
View File
@@ -311,7 +311,7 @@ describe('protections', function () {
it('no account, no passcode, biometrics', async function () {
application = await Factory.createInitAppWithFakeCrypto()
await application.enableBiometrics()
await application.protections.enableBiometrics()
expect(application.hasProtectionSources()).to.be.true
})
@@ -324,7 +324,7 @@ describe('protections', function () {
it('no account, passcode, biometrics', async function () {
application = await Factory.createInitAppWithFakeCrypto()
await application.addPasscode('passcode')
await application.enableBiometrics()
await application.protections.enableBiometrics()
expect(application.hasProtectionSources()).to.be.true
})
@@ -345,7 +345,7 @@ describe('protections', function () {
email: UuidGenerator.GenerateUuid(),
password: UuidGenerator.GenerateUuid(),
})
await application.enableBiometrics()
await application.protections.enableBiometrics()
expect(application.hasProtectionSources()).to.be.true
})
@@ -372,7 +372,7 @@ describe('protections', function () {
})
Factory.handlePasswordChallenges(application, password)
await application.addPasscode('passcode')
await application.enableBiometrics()
await application.protections.enableBiometrics()
expect(application.hasProtectionSources()).to.be.true
})
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.134.8",
"version": "2.134.9",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.5.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Features
* add free dark mode ([#1748](https://github.com/standardnotes/app/issues/1748)) ([09b994f](https://github.com/standardnotes/app/commit/09b994f8f938ae0536f42742f7a221df536c4c4a))
## [1.4.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-06-30)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/styles",
"version": "1.4.2",
"version": "1.5.0",
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
+3 -3
View File
@@ -20,14 +20,14 @@
--sn-stylekit-background-color: #ffffff;
// For borders inside background-color
--sn-stylekit-border-color: #dfe1e4;
--sn-stylekit-foreground-color: #19191C;
--sn-stylekit-foreground-color: #19191c;
// Colors for layers placed on top of non-prefixed background, border, and foreground
--sn-stylekit-contrast-background-color: rgba(244, 245, 247, 1.0);
--sn-stylekit-contrast-background-color: rgba(244, 245, 247, 1);
--sn-stylekit-contrast-foreground-color: #2e2e2e;
--sn-stylekit-contrast-border-color: #e3e3e3; // For borders inside contrast-background-color
// Alternative set of background and contrast options
--sn-stylekit-secondary-background-color: #EEEFF1;
--sn-stylekit-secondary-background-color: #eeeff1;
--sn-stylekit-secondary-foreground-color: #2e2e2e;
--sn-stylekit-secondary-border-color: #e3e3e3;
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.6.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Features
* add free dark mode ([#1748](https://github.com/standardnotes/app/issues/1748)) ([09b994f](https://github.com/standardnotes/app/commit/09b994f8f938ae0536f42742f7a221df536c4c4a))
## [1.5.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/ui-services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.5.2",
"version": "1.6.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+31 -7
View File
@@ -20,6 +20,7 @@ import {
const CachedThemesKey = 'cachedThemes'
const TimeBeforeApplyingColorScheme = 5
const DefaultThemeIdentifier = 'Default'
const DarkThemeIdentifier = 'Dark'
export class ThemeManager extends AbstractService {
private activeThemes: Uuid[] = []
@@ -90,11 +91,13 @@ export class ThemeManager extends AbstractService {
private handlePreferencesChangeEvent(): void {
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
if (useDeviceThemeSettings !== this.lastUseDeviceThemeSettings) {
const hasPreferenceChanged = useDeviceThemeSettings !== this.lastUseDeviceThemeSettings
if (hasPreferenceChanged) {
this.lastUseDeviceThemeSettings = useDeviceThemeSettings
}
if (useDeviceThemeSettings) {
if (hasPreferenceChanged && useDeviceThemeSettings) {
const prefersDarkColorScheme = window.matchMedia('(prefers-color-scheme: dark)')
this.setThemeAsPerColorScheme(prefersDarkColorScheme.matches)
@@ -159,7 +162,11 @@ export class ThemeManager extends AbstractService {
}
private colorSchemeEventHandler(event: MediaQueryListEvent) {
this.setThemeAsPerColorScheme(event.matches)
const shouldChangeTheme = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
if (shouldChangeTheme) {
this.setThemeAsPerColorScheme(event.matches)
}
}
private showColorSchemeToast(setThemeCallback: () => void) {
@@ -192,24 +199,41 @@ export class ThemeManager extends AbstractService {
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
const preference = prefersDarkColorScheme ? PrefKey.AutoDarkThemeIdentifier : PrefKey.AutoLightThemeIdentifier
const preferenceDefault =
preference === PrefKey.AutoDarkThemeIdentifier ? DarkThemeIdentifier : DefaultThemeIdentifier
const themes = this.application.items
.getDisplayableComponents()
.filter((component) => component.isTheme()) as SNTheme[]
const activeTheme = themes.find((theme) => theme.active && !theme.isLayerable())
const activeThemeIdentifier = activeTheme ? activeTheme.identifier : DefaultThemeIdentifier
const activeThemeIdentifier = activeTheme
? activeTheme.identifier
: this.application.getPreference(PrefKey.DarkMode, false)
? DarkThemeIdentifier
: DefaultThemeIdentifier
const themeIdentifier = this.application.getPreference(preference, DefaultThemeIdentifier) as string
const themeIdentifier = this.application.getPreference(preference, preferenceDefault) as string
const toggleActiveTheme = () => {
if (activeTheme) {
void this.application.mutator.toggleTheme(activeTheme)
}
}
const setTheme = () => {
if (themeIdentifier === DefaultThemeIdentifier && activeTheme) {
this.application.mutator.toggleTheme(activeTheme).catch(console.error)
if (themeIdentifier === DefaultThemeIdentifier) {
toggleActiveTheme()
void this.application.setPreference(PrefKey.DarkMode, false)
} else if (themeIdentifier === DarkThemeIdentifier) {
toggleActiveTheme()
void this.application.setPreference(PrefKey.DarkMode, true)
} else {
const theme = themes.find((theme) => theme.package_info.identifier === themeIdentifier)
if (theme && !theme.active) {
this.application.mutator.toggleTheme(theme).catch(console.error)
}
void this.application.setPreference(PrefKey.DarkMode, false)
}
}
+22
View File
@@ -3,6 +3,28 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [3.70.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* **mobile:** passcode timing options ([#1744](https://github.com/standardnotes/app/issues/1744)) ([6c26b96](https://github.com/standardnotes/app/commit/6c26b96cdce0d69a4a459104709880850a401a92))
### Features
* add free dark mode ([#1748](https://github.com/standardnotes/app/issues/1748)) ([09b994f](https://github.com/standardnotes/app/commit/09b994f8f938ae0536f42742f7a221df536c4c4a))
## [3.69.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Bug Fixes
* prevent overflow bouncing on desktop and mobile ([#1743](https://github.com/standardnotes/app/issues/1743)) ([6bd5534](https://github.com/standardnotes/app/commit/6bd5534f749a35b5ddc35cb09115358ce9ee4115))
# [3.69.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
### Features
* add file info panel button to file view ([#1741](https://github.com/standardnotes/app/issues/1741)) ([376810e](https://github.com/standardnotes/app/commit/376810e657b5dace6cc342b7298bb00abd311587))
## [3.68.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-05)
**Note:** Version bump only for package @standardnotes/web
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.68.6",
"version": "3.70.0",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -32,7 +32,7 @@ import { PrefDefaults } from '@/Constants/PrefDefaults'
type WebServices = {
viewControllerManager: ViewControllerManager
desktopService?: DesktopManager
autolockService: AutolockService
autolockService?: AutolockService
archiveService: ArchiveManager
themeService: ThemeManager
io: IOService
@@ -237,7 +237,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
async handleMobileGainingFocusEvent(): Promise<void> {}
async handleMobileLosingFocusEvent(): Promise<void> {
if (this.getMobileScreenshotPrivacyEnabled()) {
if (this.protections.getMobileScreenshotPrivacyEnabled()) {
this.mobileDevice().stopHidingMobileInterfaceFromScreenshots()
}
@@ -245,7 +245,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
}
async handleMobileResumingFromBackgroundEvent(): Promise<void> {
if (this.getMobileScreenshotPrivacyEnabled()) {
if (this.protections.getMobileScreenshotPrivacyEnabled()) {
this.mobileDevice().hideMobileInterfaceFromScreenshots()
}
}
@@ -256,10 +256,10 @@ export class WebApplication extends SNApplication implements WebApplicationInter
return
}
const hasBiometrics = this.hasBiometrics()
const hasBiometrics = this.protections.hasBiometricsEnabled()
const hasPasscode = this.hasPasscode()
const passcodeTiming = await this.getMobilePasscodeTiming()
const biometricsTiming = await this.getMobileBiometricsTiming()
const passcodeTiming = this.protections.getMobilePasscodeTiming()
const biometricsTiming = this.protections.getMobileBiometricsTiming()
const passcodeLockImmediately = hasPasscode && passcodeTiming === MobileUnlockTiming.Immediately
const biometricsLockImmediately = hasBiometrics && biometricsTiming === MobileUnlockTiming.Immediately
@@ -34,7 +34,6 @@ const createApplication = (
const archiveService = new ArchiveManager(application)
const io = new IOService(platform === Platform.MacWeb || platform === Platform.MacDesktop)
const internalEventBus = new InternalEventBus()
const autolockService = new AutolockService(application, internalEventBus)
const themeService = new ThemeManager(application, internalEventBus)
application.setWebServices({
@@ -42,7 +41,7 @@ const createApplication = (
archiveService,
desktopService: isDesktopDevice(device) ? new DesktopManager(application, device) : undefined,
io,
autolockService,
autolockService: application.isNativeMobileWeb() ? undefined : new AutolockService(application, internalEventBus),
themeService,
})
@@ -27,6 +27,7 @@ import FileDragNDropProvider from '../FileDragNDropProvider/FileDragNDropProvide
import ResponsivePaneProvider from '../ResponsivePane/ResponsivePaneProvider'
import AndroidBackHandlerProvider from '@/NativeMobileWeb/useAndroidBackHandler'
import ConfirmDeleteAccountContainer from '@/Components/ConfirmDeleteAccountModal/ConfirmDeleteAccountModal'
import DarkModeHandler from '../DarkModeHandler/DarkModeHandler'
type Props = {
application: WebApplication
@@ -190,6 +191,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
return (
<AndroidBackHandlerProvider application={application}>
<DarkModeHandler application={application} />
<ResponsivePaneProvider>
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
<div className={platformString + ' main-ui-view sn-component'}>
@@ -0,0 +1,26 @@
import { WebApplication } from '@/Application/Application'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import { ApplicationEvent, PrefKey } from '@standardnotes/snjs'
import { useEffect } from 'react'
type Props = {
application: WebApplication
}
const DarkModeHandler = ({ application }: Props) => {
useEffect(() => {
application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
const isDarkModeOn = application.getPreference(PrefKey.DarkMode, PrefDefaults[PrefKey.DarkMode])
if (isDarkModeOn) {
document.documentElement.classList.add('dark-mode')
} else {
document.documentElement.classList.remove('dark-mode')
}
})
}, [application])
return null
}
export default DarkModeHandler
@@ -42,17 +42,6 @@ const FileMenuOptions: FunctionComponent<Props> = ({
[selectedFiles],
)
const onPreview = useCallback(() => {
void handleFileAction({
type: PopoverFileItemActionType.PreviewFile,
payload: {
file: selectedFiles[0],
otherFiles: selectedFiles.length > 1 ? selectedFiles : filesController.allFiles,
},
})
closeMenu()
}, [closeMenu, filesController.allFiles, handleFileAction, selectedFiles])
const onDetach = useCallback(() => {
const file = selectedFiles[0]
void handleFileAction({
@@ -78,10 +67,6 @@ const FileMenuOptions: FunctionComponent<Props> = ({
return (
<>
<MenuItem onClick={onPreview}>
<Icon type="file" className="mr-2 text-neutral" />
Preview file
</MenuItem>
{selectedFiles.length === 1 && (
<>
{isFileAttachedToNote ? (
@@ -97,7 +82,6 @@ const FileMenuOptions: FunctionComponent<Props> = ({
) : null}
</>
)}
<HorizontalSeparator classes="my-1" />
<MenuItem
type={MenuItemType.SwitchButton}
checked={hasProtectedFiles}
@@ -1,16 +1,25 @@
import { ElementIds } from '@/Constants/ElementIDs'
import { observer } from 'mobx-react-lite'
import { ChangeEventHandler, useCallback, useRef } from 'react'
import { ChangeEventHandler, useCallback, useRef, useState } from 'react'
import FileOptionsPanel from '@/Components/FileContextMenu/FileOptionsPanel'
import FilePreview from '@/Components/FilePreview/FilePreview'
import { FileViewProps } from './FileViewProps'
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
import Icon from '../Icon/Icon'
import Popover from '../Popover/Popover'
import FilePreviewInfoPanel from '../FilePreview/FilePreviewInfoPanel'
const SyncTimeoutNoDebounceMs = 100
const SyncTimeoutDebounceMs = 350
const FileViewWithoutProtection = ({ application, viewControllerManager, file }: FileViewProps) => {
const syncTimeoutRef = useRef<number>()
const fileInfoButtonRef = useRef<HTMLButtonElement>(null)
const [isFileInfoPanelOpen, setIsFileInfoPanelOpen] = useState(false)
const toggleFileInfoPanel = () => {
setIsFileInfoPanelOpen((show) => !show)
}
const onTitleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
async (event) => {
@@ -53,7 +62,25 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
/>
</div>
</div>
<div className="flex items-center">
<div className="flex items-center gap-3">
<button
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
title="File information panel"
aria-label="File information panel"
onClick={toggleFileInfoPanel}
ref={fileInfoButtonRef}
>
<Icon type="info" />
</button>
<Popover
open={isFileInfoPanelOpen}
togglePopover={toggleFileInfoPanel}
anchorElement={fileInfoButtonRef.current}
side="bottom"
align="center"
>
<FilePreviewInfoPanel file={file} />
</Popover>
<FileOptionsPanel
filesController={viewControllerManager.filesController}
selectionController={viewControllerManager.selectionController}
@@ -61,6 +61,7 @@ const PositionedPopoverContent = ({
'absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
overrideZIndex ? overrideZIndex : 'z-dropdown-menu',
!isDesktopScreen ? 'pt-safe-top pb-safe-bottom' : '',
!styles && 'md:invisible',
)}
style={{
...styles,
@@ -4,7 +4,7 @@ import { usePremiumModal } from '@/Hooks/usePremiumModal'
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
import Switch from '@/Components/Switch/Switch'
import { WebApplication } from '@/Application/Application'
import { ContentType, FeatureIdentifier, FeatureStatus, PrefKey, GetFeatures, SNTheme } from '@standardnotes/snjs'
import { ContentType, FeatureIdentifier, PrefKey, GetFeatures, SNTheme } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useEffect, useState } from 'react'
import { Subtitle, Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
@@ -21,18 +21,13 @@ type Props = {
const Appearance: FunctionComponent<Props> = ({ application }) => {
const premiumModal = usePremiumModal()
const isEntitledToMidnightTheme =
application.features.getFeatureStatus(FeatureIdentifier.MidnightTheme) === FeatureStatus.Entitled
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
const [autoLightTheme, setAutoLightTheme] = useState<string>(() =>
application.getPreference(PrefKey.AutoLightThemeIdentifier, PrefDefaults[PrefKey.AutoLightThemeIdentifier]),
)
const [autoDarkTheme, setAutoDarkTheme] = useState<string>(() =>
application.getPreference(
PrefKey.AutoDarkThemeIdentifier,
isEntitledToMidnightTheme ? FeatureIdentifier.MidnightTheme : PrefDefaults[PrefKey.AutoDarkThemeIdentifier],
),
application.getPreference(PrefKey.AutoDarkThemeIdentifier, PrefDefaults[PrefKey.AutoDarkThemeIdentifier]),
)
const [useDeviceSettings, setUseDeviceSettings] = useState(() =>
application.getPreference(PrefKey.UseSystemColorScheme, PrefDefaults[PrefKey.UseSystemColorScheme]),
@@ -63,6 +58,11 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
}
})
themesAsItems.unshift({
label: 'Dark',
value: 'Dark',
})
themesAsItems.unshift({
label: 'Default',
value: 'Default',
@@ -16,10 +16,12 @@ type Props = {
const BiometricsLock = ({ application }: Props) => {
const [hasBiometrics, setHasBiometrics] = useState(false)
const [supportsBiometrics, setSupportsBiometrics] = useState(false)
const [biometricsTimingOptions, setBiometricsTimingOptions] = useState(() => application.getBiometricsTimingOptions())
const [biometricsTimingOptions, setBiometricsTimingOptions] = useState(() =>
application.protections.getMobileBiometricsTimingOptions(),
)
useEffect(() => {
const appHasBiometrics = application.hasBiometrics()
const appHasBiometrics = application.protections.hasBiometricsEnabled()
setHasBiometrics(appHasBiometrics)
const hasBiometricsSupport = async () => {
@@ -32,12 +34,12 @@ const BiometricsLock = ({ application }: Props) => {
}, [application])
const setBiometricsTimingValue = async (timing: MobileUnlockTiming) => {
await application.setBiometricsTiming(timing)
setBiometricsTimingOptions(() => application.getBiometricsTimingOptions())
application.protections.setMobileBiometricsTiming(timing)
setBiometricsTimingOptions(() => application.protections.getMobileBiometricsTimingOptions())
}
const disableBiometrics = useCallback(async () => {
if (await application.disableBiometrics()) {
if (await application.protections.disableBiometrics()) {
setHasBiometrics(false)
}
}, [application])
@@ -47,7 +49,7 @@ const BiometricsLock = ({ application }: Props) => {
await disableBiometrics()
} else {
setHasBiometrics(true)
application.enableBiometrics()
application.protections.enableBiometrics()
await setBiometricsTimingValue(MobileUnlockTiming.OnQuit)
}
}
@@ -16,7 +16,7 @@ const MultitaskingPrivacy = ({ application }: Props) => {
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean>(false)
useEffect(() => {
const hasScreenshotPrivacyEnabled = application.getMobileScreenshotPrivacyEnabled()
const hasScreenshotPrivacyEnabled = application.protections.getMobileScreenshotPrivacyEnabled()
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}, [application])
@@ -24,7 +24,7 @@ const MultitaskingPrivacy = ({ application }: Props) => {
const enable = !hasScreenshotPrivacy
setHasScreenshotPrivacy(enable)
application.setMobileScreenshotPrivacyEnabled(enable)
application.protections.setMobileScreenshotPrivacyEnabled(enable)
;(application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enable)
}
@@ -12,7 +12,7 @@ import { WebApplication } from '@/Application/Application'
import { preventRefreshing } from '@/Utils'
import { alertDialog } from '@standardnotes/ui-services'
import { FormEvent, useCallback, useEffect, useRef, useState } from 'react'
import { ApplicationEvent } from '@standardnotes/snjs'
import { ApplicationEvent, MobileUnlockTiming } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
import { Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
@@ -28,8 +28,8 @@ type Props = {
}
const PasscodeLock = ({ application, viewControllerManager }: Props) => {
const isNativeMobileWeb = application.isNativeMobileWeb()
const keyStorageInfo = StringUtils.keyStorageInfo(application)
const passcodeAutoLockOptions = application.getAutolockService().getAutoLockIntervalOptions()
const { setIsEncryptionEnabled, setIsBackupEncrypted, setEncryptionStatusString } =
viewControllerManager.accountMenuController
@@ -44,6 +44,10 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
const [canAddPasscode, setCanAddPasscode] = useState(!application.isEphemeralSession())
const [hasPasscode, setHasPasscode] = useState(application.hasPasscode())
const [mobilePasscodeTimingOptions, setMobilePasscodeTimingOptions] = useState(() =>
application.protections.getMobilePasscodeTimingOptions(),
)
const handleAddPassCode = () => {
setShowPasscodeForm(true)
setIsPasscodeFocused(true)
@@ -53,8 +57,8 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
handleAddPassCode()
}
const reloadAutoLockInterval = useCallback(async () => {
const interval = await application.getAutolockService().getAutoLockInterval()
const reloadDesktopAutoLockInterval = useCallback(async () => {
const interval = await application.getAutolockService()!.getAutoLockInterval()
setSelectedAutoLockInterval(interval)
}, [application])
@@ -77,19 +81,27 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
setIsBackupEncrypted(encryptionEnabled)
}, [application, setEncryptionStatusString, setIsBackupEncrypted, setIsEncryptionEnabled])
const selectAutoLockInterval = async (interval: number) => {
const selectDesktopAutoLockInterval = async (interval: number) => {
if (!(await application.authorizeAutolockIntervalChange())) {
return
}
await application.getAutolockService().setAutoLockInterval(interval)
reloadAutoLockInterval().catch(console.error)
await application.getAutolockService()!.setAutoLockInterval(interval)
reloadDesktopAutoLockInterval().catch(console.error)
}
const setMobilePasscodeTiming = (timing: MobileUnlockTiming) => {
application.protections.setMobilePasscodeTiming(timing)
setMobilePasscodeTimingOptions(application.protections.getMobilePasscodeTimingOptions())
}
const removePasscodePressed = async () => {
await preventRefreshing(STRING_CONFIRM_APP_QUIT_DURING_PASSCODE_REMOVAL, async () => {
if (await application.removePasscode()) {
await application.getAutolockService().deleteAutolockPreference()
await reloadAutoLockInterval()
if (!isNativeMobileWeb) {
await application.getAutolockService()?.deleteAutolockPreference()
await reloadDesktopAutoLockInterval()
}
refreshEncryptionStatus()
}
})
@@ -141,11 +153,11 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
refreshEncryptionStatus()
}, [refreshEncryptionStatus])
// `reloadAutoLockInterval` gets interval asynchronously, therefore we call `useEffect` to set initial
// value of `selectedAutoLockInterval`
useEffect(() => {
reloadAutoLockInterval().catch(console.error)
}, [reloadAutoLockInterval])
if (!isNativeMobileWeb) {
reloadDesktopAutoLockInterval().catch(console.error)
}
}, [reloadDesktopAutoLockInterval, isNativeMobileWeb])
useEffect(() => {
if (isPasscodeFocused) {
@@ -154,7 +166,6 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
}
}, [isPasscodeFocused])
// Add the required event observers
useEffect(() => {
const removeKeyStatusChangedObserver = application.addEventObserver(async () => {
setCanAddPasscode(!application.isEphemeralSession())
@@ -229,7 +240,7 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
</PreferencesSegment>
</PreferencesGroup>
{hasPasscode && (
{hasPasscode && !isNativeMobileWeb && (
<>
<div className="min-h-3" />
<PreferencesGroup>
@@ -237,22 +248,57 @@ const PasscodeLock = ({ application, viewControllerManager }: Props) => {
<Title>Autolock</Title>
<Text className="mb-3">The autolock timer begins when the window or tab loses focus.</Text>
<div className="flex flex-row items-center">
{passcodeAutoLockOptions.map((option) => {
return (
<a
key={option.value}
className={classNames(
'mr-3 cursor-pointer rounded',
option.value === selectedAutoLockInterval
? 'bg-info px-1.5 py-0.5 text-info-contrast'
: 'text-info',
)}
onClick={() => selectAutoLockInterval(option.value)}
>
{option.label}
</a>
)
})}
{application
.getAutolockService()!
.getAutoLockIntervalOptions()
.map((option) => {
return (
<a
key={option.value}
className={classNames(
'mr-3 cursor-pointer rounded',
option.value === selectedAutoLockInterval
? 'bg-info px-1.5 py-0.5 text-info-contrast'
: 'text-info',
)}
onClick={() => selectDesktopAutoLockInterval(option.value)}
>
{option.label}
</a>
)
})}
</div>
</PreferencesSegment>
</PreferencesGroup>
</>
)}
{hasPasscode && isNativeMobileWeb && (
<>
<div className="min-h-3" />
<PreferencesGroup>
<PreferencesSegment>
<Title>Passcode Autolock</Title>
<div className="flex flex-row items-center">
<div className="mt-2 flex flex-row items-center">
<div className={'mr-3'}>Require Passcode</div>
{mobilePasscodeTimingOptions.map((option) => {
return (
<a
key={option.key}
className={classNames(
'mr-3 cursor-pointer rounded px-1.5 py-0.5',
option.selected ? 'bg-info text-info-contrast' : 'text-info',
)}
onClick={() => {
void setMobilePasscodeTiming(option.key as MobileUnlockTiming)
}}
>
{option.title}
</a>
)
})}
</div>
</div>
</PreferencesSegment>
</PreferencesGroup>
@@ -1,5 +1,13 @@
import { WebApplication } from '@/Application/Application'
import { ComponentArea, ContentType, FeatureIdentifier, GetFeatures, SNComponent } from '@standardnotes/snjs'
import {
ApplicationEvent,
ComponentArea,
ContentType,
FeatureIdentifier,
GetFeatures,
PrefKey,
SNComponent,
} from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
import Icon from '@/Components/Icon/Icon'
@@ -12,6 +20,7 @@ import RadioIndicator from '../RadioIndicator/RadioIndicator'
import HorizontalSeparator from '../Shared/HorizontalSeparator'
import { QuickSettingsController } from '@/Controllers/QuickSettingsController'
import PanelSettingsSection from './PanelSettingsSection'
import { PrefDefaults } from '@/Constants/PrefDefaults'
const focusModeAnimationDuration = 1255
@@ -38,7 +47,19 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
const { closeQuickSettingsMenu, focusModeEnabled, setFocusModeEnabled } = quickSettingsMenuController
const [themes, setThemes] = useState<ThemeItem[]>([])
const [toggleableComponents, setToggleableComponents] = useState<SNComponent[]>([])
const [defaultThemeOn, setDefaultThemeOn] = useState(false)
const [isDarkModeOn, setDarkModeOn] = useState(
application.getPreference(PrefKey.DarkMode, PrefDefaults[PrefKey.DarkMode]),
)
const defaultThemeOn =
!themes.map((item) => item?.component).find((theme) => theme?.active && !theme.isLayerable()) && !isDarkModeOn
useEffect(() => {
application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
const isDarkModeOn = application.getPreference(PrefKey.DarkMode, PrefDefaults[PrefKey.DarkMode])
setDarkModeOn(isDarkModeOn)
})
}, [application])
const prefsButtonRef = useRef<HTMLButtonElement>(null)
const defaultThemeButtonRef = useRef<HTMLButtonElement>(null)
@@ -73,8 +94,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
})
setThemes(themes.sort(sortThemes))
setDefaultThemeOn(!themes.map((item) => item?.component).find((theme) => theme?.active && !theme.isLayerable()))
}, [application])
const reloadToggleableComponents = useCallback(() => {
@@ -131,13 +150,25 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
[application],
)
const toggleDefaultTheme = useCallback(() => {
const deactivateAnyNonLayerableTheme = useCallback(() => {
const activeTheme = themes.map((item) => item.component).find((theme) => theme?.active && !theme.isLayerable())
if (activeTheme) {
application.mutator.toggleTheme(activeTheme).catch(console.error)
}
}, [application, themes])
const toggleDefaultTheme = useCallback(() => {
deactivateAnyNonLayerableTheme()
application.setPreference(PrefKey.DarkMode, false)
}, [application, deactivateAnyNonLayerableTheme])
const toggleDarkMode = useCallback(() => {
if (!isDarkModeOn) {
deactivateAnyNonLayerableTheme()
application.setPreference(PrefKey.DarkMode, true)
}
}, [application, isDarkModeOn, deactivateAnyNonLayerableTheme])
return (
<div ref={mainRef}>
<div className="my-1 px-3 text-sm font-semibold uppercase text-text">Themes</div>
@@ -149,6 +180,13 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
<RadioIndicator checked={defaultThemeOn} className="mr-2" />
Default
</button>
<button
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
onClick={toggleDarkMode}
>
<RadioIndicator checked={isDarkModeOn} className="mr-2" />
Dark
</button>
{themes.map((theme) => (
<ThemesMenuButton item={theme} application={application} key={theme.component?.uuid ?? theme.identifier} />
))}
@@ -1,5 +1,5 @@
import { WebApplication } from '@/Application/Application'
import { FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
import { FeatureIdentifier, FeatureStatus, PrefKey } from '@standardnotes/snjs'
import { FunctionComponent, MouseEventHandler, useCallback, useMemo } from 'react'
import Icon from '@/Components/Icon/Icon'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
@@ -32,10 +32,15 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ application, item }) => {
e.preventDefault()
if (item.component && canActivateTheme) {
const themeIsLayerableOrNotActive = item.component.isLayerable() || !item.component.active
const isThemeLayerable = item.component.isLayerable()
const themeIsLayerableOrNotActive = isThemeLayerable || !item.component.active
if (themeIsLayerableOrNotActive) {
application.mutator.toggleTheme(item.component).catch(console.error)
if (!isThemeLayerable) {
application.setPreference(PrefKey.DarkMode, false)
}
}
} else {
premiumModal.activate(`${item.name} theme`)
@@ -22,9 +22,10 @@ export const PrefDefaults = {
[PrefKey.NotesHideEditorIcon]: false,
[PrefKey.UseSystemColorScheme]: false,
[PrefKey.AutoLightThemeIdentifier]: 'Default',
[PrefKey.AutoDarkThemeIdentifier]: 'Default',
[PrefKey.AutoDarkThemeIdentifier]: 'Dark',
[PrefKey.NoteAddToParentFolders]: true,
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
[PrefKey.UpdateSavingStatusIndicator]: true,
[PrefKey.DarkMode]: false,
} as const
@@ -0,0 +1,71 @@
.dark-mode {
--foreground-color: #eeeeee;
--background-color: #0f1011;
--highlight-color: #a464c2;
--border-color: #0f1011;
--sn-component-foreground-color: var(--foreground-color);
--sn-component-background-color: transparent;
--sn-component-foreground-highlight-color: var(--highlight-color);
--sn-component-outer-border-color: transparent;
--sn-component-inner-border-color: var(--foreground-color);
// StyleKit Vars
--sn-stylekit-passive-color-0: #999999;
--sn-stylekit-passive-color-3: #28292b;
--sn-stylekit-passive-color-4: #1c1d1e;
--sn-stylekit-passive-color-5: #1d1f20;
--sn-stylekit-shadow-color: #000000;
--sn-stylekit-info-color: var(--highlight-color);
--sn-stylekit-info-contrast-color: var(--foreground-color);
--sn-stylekit-neutral-color: #7c7c7c;
--sn-stylekit-neutral-contrast-color: #ffffff;
--sn-stylekit-success-color: #2b9612;
--sn-stylekit-success-contrast-color: #ffffff;
--sn-stylekit-warning-color: #f6a200;
--sn-stylekit-warning-contrast-color: #ffffff;
--sn-stylekit-danger-color: #f80324;
--sn-stylekit-danger-contrast-color: #ffffff;
--sn-stylekit-editor-background-color: var(--sn-stylekit-background-color);
--sn-stylekit-editor-foreground-color: var(--sn-stylekit-foreground-color);
--sn-stylekit-background-color: var(--background-color);
--sn-stylekit-foreground-color: var(--foreground-color);
--sn-stylekit-border-color: #000000;
--sn-stylekit-contrast-background-color: #000000;
--sn-stylekit-contrast-foreground-color: #ffffff;
--sn-stylekit-contrast-border-color: #000000;
--sn-stylekit-secondary-background-color: var(--sn-stylekit-passive-color-4);
--sn-stylekit-secondary-foreground-color: #ffffff;
--sn-stylekit-secondary-border-color: #000000;
--sn-stylekit-secondary-contrast-background-color: #000000;
--sn-stylekit-secondary-contrast-foreground-color: #ffffff;
--sn-stylekit-secondary-contrast-border-color: #ffffff;
--sn-stylekit-paragraph-text-color: #ffffff;
--sn-desktop-titlebar-bg-color: var(--background-color);
--sn-desktop-titlebar-border-color: var(--border-color);
--sn-desktop-titlebar-ui-color: var(--foreground-color);
--sn-desktop-titlebar-ui-hover-color: var(--highlight-color);
--sn-stylekit-scrollbar-track-border-color: var(--border-color);
--sn-stylekit-scrollbar-thumb-color: var(--sn-stylekit-info-color);
--sn-stylekit-menu-border: 1px solid #424242;
// Theme
--navigation-item-selected-background-color: var(--background-color);
}
+1
View File
@@ -55,6 +55,7 @@ body {
* {
box-sizing: border-box;
overscroll-behavior: none;
}
.uppercase {
@@ -3,6 +3,7 @@
@import '../../../styles/src/Styles/_scrollbar.scss';
@import '../../../styles/src/Styles/utils/_animation.scss';
@import 'theme';
@import 'dark-mode';
@import 'main';
@import 'ui';
@import 'footer';