diff --git a/app/assets/javascripts/components/Dropdown.tsx b/app/assets/javascripts/components/Dropdown.tsx index b43a63804..837697520 100644 --- a/app/assets/javascripts/components/Dropdown.tsx +++ b/app/assets/javascripts/components/Dropdown.tsx @@ -8,7 +8,8 @@ import { } from '@reach/listbox'; import VisuallyHidden from '@reach/visually-hidden'; import { FunctionComponent } from 'preact'; -import { IconType, Icon } from './Icon'; +import { Icon } from './Icon'; +import { IconType } from '@standardnotes/snjs'; export type DropdownItem = { icon?: IconType; diff --git a/app/assets/javascripts/components/Icon.tsx b/app/assets/javascripts/components/Icon.tsx index 73f9d92fa..c5aa62cd2 100644 --- a/app/assets/javascripts/components/Icon.tsx +++ b/app/assets/javascripts/components/Icon.tsx @@ -67,6 +67,7 @@ import MenuArrowDownAlt from '../../icons/ic-menu-arrow-down-alt.svg'; import MenuArrowRight from '../../icons/ic-menu-arrow-right.svg'; import { FunctionalComponent } from 'preact'; +import { IconType } from '@standardnotes/snjs'; const ICONS = { editor: EditorIcon, @@ -137,8 +138,6 @@ const ICONS = { 'premium-feature': PremiumFeatureIcon, }; -export type IconType = keyof typeof ICONS; - type Props = { type: IconType; className?: string; diff --git a/app/assets/javascripts/components/IconButton.tsx b/app/assets/javascripts/components/IconButton.tsx index 45ce99942..c45233a99 100644 --- a/app/assets/javascripts/components/IconButton.tsx +++ b/app/assets/javascripts/components/IconButton.tsx @@ -1,5 +1,6 @@ import { FunctionComponent } from 'preact'; -import { Icon, IconType } from './Icon'; +import { Icon } from './Icon'; +import { IconType } from '@standardnotes/snjs'; interface Props { /** diff --git a/app/assets/javascripts/components/InputWithIcon.tsx b/app/assets/javascripts/components/InputWithIcon.tsx index 7f228df3b..733a6ed3c 100644 --- a/app/assets/javascripts/components/InputWithIcon.tsx +++ b/app/assets/javascripts/components/InputWithIcon.tsx @@ -1,8 +1,9 @@ import { FunctionComponent, Ref } from 'preact'; import { JSXInternal } from 'preact/src/jsx'; import { forwardRef } from 'preact/compat'; -import { Icon, IconType } from './Icon'; +import { Icon } from './Icon'; import { IconButton } from './IconButton'; +import { IconType } from '@standardnotes/snjs'; type ToggleProps = { toggleOnIcon: IconType; diff --git a/app/assets/javascripts/components/NotesListItem.tsx b/app/assets/javascripts/components/NotesListItem.tsx index 806be8916..975191fab 100644 --- a/app/assets/javascripts/components/NotesListItem.tsx +++ b/app/assets/javascripts/components/NotesListItem.tsx @@ -1,4 +1,3 @@ -import { getIconAndTintForEditor } from '@/preferences/panes/general-segments'; import { WebApplication } from '@/ui_models/application'; import { CollectionSort, @@ -74,7 +73,9 @@ export const NotesListItem: FunctionComponent = ({ const showModifiedDate = sortedBy === CollectionSort.UpdatedAt; const editorForNote = application.componentManager.editorForNote(note); const editorName = editorForNote?.name ?? 'Plain editor'; - const [icon, tint] = getIconAndTintForEditor(editorForNote?.identifier); + const [icon, tint] = application.iconsController.getIconAndTintForEditor( + editorForNote?.identifier + ); return (
= ( return ( diff --git a/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx b/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx index c82b79878..b8270a872 100644 --- a/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx +++ b/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx @@ -1,8 +1,8 @@ -import { Icon, IconType } from '@/components/Icon'; +import { Icon } from '@/components/Icon'; import { FeaturesState } from '@/ui_models/app_state/features_state'; import { TagsState } from '@/ui_models/app_state/tags_state'; import '@reach/tooltip/styles.css'; -import { SNSmartTag } from '@standardnotes/snjs'; +import { SNSmartTag, IconType } from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; import { FunctionComponent } from 'preact'; import { useCallback, useEffect, useRef, useState } from 'preact/hooks'; diff --git a/app/assets/javascripts/components/menu/MenuItem.tsx b/app/assets/javascripts/components/menu/MenuItem.tsx index c275fa916..726c898cf 100644 --- a/app/assets/javascripts/components/menu/MenuItem.tsx +++ b/app/assets/javascripts/components/menu/MenuItem.tsx @@ -6,8 +6,9 @@ import { } from 'preact'; import { forwardRef, Ref } from 'preact/compat'; import { JSXInternal } from 'preact/src/jsx'; -import { Icon, IconType } from '../Icon'; +import { Icon } from '../Icon'; import { Switch, SwitchProps } from '../Switch'; +import { IconType } from '@standardnotes/snjs'; export enum MenuItemType { IconButton, diff --git a/app/assets/javascripts/preferences/PreferencesMenu.ts b/app/assets/javascripts/preferences/PreferencesMenu.ts index 47e29f05a..78966c71d 100644 --- a/app/assets/javascripts/preferences/PreferencesMenu.ts +++ b/app/assets/javascripts/preferences/PreferencesMenu.ts @@ -1,4 +1,3 @@ -import { IconType } from '@/components/Icon'; import { action, makeAutoObservable, observable } from 'mobx'; import { ExtensionsLatestVersions } from '@/preferences/panes/extensions-segments'; import { @@ -6,6 +5,7 @@ import { ContentType, FeatureIdentifier, SNComponent, + IconType, } from '@standardnotes/snjs'; import { WebApplication } from '@/ui_models/application'; diff --git a/app/assets/javascripts/preferences/components/MenuItem.tsx b/app/assets/javascripts/preferences/components/MenuItem.tsx index 66b34d288..900ed8304 100644 --- a/app/assets/javascripts/preferences/components/MenuItem.tsx +++ b/app/assets/javascripts/preferences/components/MenuItem.tsx @@ -1,5 +1,6 @@ -import { Icon, IconType } from '@/components/Icon'; +import { Icon } from '@/components/Icon'; import { FunctionComponent } from 'preact'; +import { IconType } from '@standardnotes/snjs'; interface Props { iconType: IconType; diff --git a/app/assets/javascripts/preferences/panes/Appearance.tsx b/app/assets/javascripts/preferences/panes/Appearance.tsx index 6419eb6a0..7ab72acd7 100644 --- a/app/assets/javascripts/preferences/panes/Appearance.tsx +++ b/app/assets/javascripts/preferences/panes/Appearance.tsx @@ -142,7 +142,8 @@ const AppearancePane: FunctionComponent = observer(({ application }) => {
Use system color scheme - Automatically change active theme based on your system settings. + Automatically change active theme based on your system + settings.
= ({ - application, - providerName - }) => { + application, + providerName, +}) => { const [authBegan, setAuthBegan] = useState(false); const [successfullyInstalled, setSuccessfullyInstalled] = useState(false); const [backupFrequency, setBackupFrequency] = useState(null); @@ -32,14 +32,13 @@ export const CloudBackupProvider: FunctionComponent = ({ event.stopPropagation(); try { - const shouldDisable = await application.alertService - .confirm( - 'Are you sure you want to disable this integration?', - 'Disable?', - 'Disable', - ButtonType.Danger, - 'Cancel' - ); + const shouldDisable = await application.alertService.confirm( + 'Are you sure you want to disable this integration?', + 'Disable?', + 'Disable', + ButtonType.Danger, + 'Cancel' + ); if (shouldDisable) { await application.deleteSetting(backupFrequencySettingName); await application.deleteSetting(backupTokenSettingName); @@ -54,7 +53,10 @@ export const CloudBackupProvider: FunctionComponent = ({ const installIntegration = (event: Event) => { event.stopPropagation(); - const authUrl = application.getCloudProviderIntegrationUrl(providerName, isDev); + const authUrl = application.getCloudProviderIntegrationUrl( + providerName, + isDev + ); openInNewTab(authUrl); setAuthBegan(true); }; @@ -62,7 +64,10 @@ export const CloudBackupProvider: FunctionComponent = ({ const performBackupNow = async () => { // A backup is performed anytime the setting is updated with the integration token, so just update it here try { - await application.updateSetting(backupFrequencySettingName, backupFrequency as string); + await application.updateSetting( + backupFrequencySettingName, + backupFrequency as string + ); application.alertService.alert( 'A backup has been triggered for this provider. Please allow a couple minutes for your backup to be processed.' ); @@ -77,20 +82,24 @@ export const CloudBackupProvider: FunctionComponent = ({ [CloudProvider.Dropbox]: { backupTokenSettingName: SettingName.DropboxBackupToken, backupFrequencySettingName: SettingName.DropboxBackupFrequency, - defaultBackupFrequency: DropboxBackupFrequency.Daily + defaultBackupFrequency: DropboxBackupFrequency.Daily, }, [CloudProvider.Google]: { backupTokenSettingName: SettingName.GoogleDriveBackupToken, backupFrequencySettingName: SettingName.GoogleDriveBackupFrequency, - defaultBackupFrequency: GoogleDriveBackupFrequency.Daily + defaultBackupFrequency: GoogleDriveBackupFrequency.Daily, }, [CloudProvider.OneDrive]: { backupTokenSettingName: SettingName.OneDriveBackupToken, backupFrequencySettingName: SettingName.OneDriveBackupFrequency, - defaultBackupFrequency: OneDriveBackupFrequency.Daily - } + defaultBackupFrequency: OneDriveBackupFrequency.Daily, + }, }; - const { backupTokenSettingName, backupFrequencySettingName, defaultBackupFrequency } = backupSettingsData[providerName]; + const { + backupTokenSettingName, + backupFrequencySettingName, + defaultBackupFrequency, + } = backupSettingsData[providerName]; const getCloudProviderIntegrationTokenFromUrl = (url: URL) => { const urlSearchParams = new URLSearchParams(url.search); @@ -123,8 +132,14 @@ export const CloudBackupProvider: FunctionComponent = ({ if (!cloudProviderToken) { throw new Error(); } - await application.updateSetting(backupTokenSettingName, cloudProviderToken); - await application.updateSetting(backupFrequencySettingName, defaultBackupFrequency); + await application.updateSetting( + backupTokenSettingName, + cloudProviderToken + ); + await application.updateSetting( + backupFrequencySettingName, + defaultBackupFrequency + ); setBackupFrequency(defaultBackupFrequency); @@ -174,15 +189,15 @@ export const CloudBackupProvider: FunctionComponent = ({
{authBegan && (
-

+

Complete authentication from the newly opened window. Upon completion, a confirmation code will be displayed. Enter this code below:

= ({ {shouldShowEnableButton && (
diff --git a/app/assets/javascripts/preferences/panes/backups-segments/cloud-backups/index.tsx b/app/assets/javascripts/preferences/panes/backups-segments/cloud-backups/index.tsx index 19dc52ffe..f33aa207a 100644 --- a/app/assets/javascripts/preferences/panes/backups-segments/cloud-backups/index.tsx +++ b/app/assets/javascripts/preferences/panes/backups-segments/cloud-backups/index.tsx @@ -4,26 +4,34 @@ import { useCallback, useEffect, useState } from 'preact/hooks'; import { WebApplication } from '@/ui_models/application'; import { PreferencesGroup, - PreferencesSegment, Subtitle, + PreferencesSegment, + Subtitle, Text, - Title + Title, } from '@/preferences/components'; import { HorizontalSeparator } from '@/components/shared/HorizontalSeparator'; import { FeatureIdentifier } from '@standardnotes/features'; import { FeatureStatus } from '@standardnotes/snjs'; import { FunctionComponent } from 'preact'; -import { CloudProvider, EmailBackupFrequency, SettingName } from '@standardnotes/settings'; +import { + CloudProvider, + EmailBackupFrequency, + SettingName, +} from '@standardnotes/settings'; import { Switch } from '@/components/Switch'; import { convertStringifiedBooleanToBoolean } from '@/utils'; import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/strings'; -const providerData = [{ - name: CloudProvider.Dropbox -}, { - name: CloudProvider.Google -}, { - name: CloudProvider.OneDrive -} +const providerData = [ + { + name: CloudProvider.Dropbox, + }, + { + name: CloudProvider.Google, + }, + { + name: CloudProvider.OneDrive, + }, ]; type Props = { @@ -31,8 +39,10 @@ type Props = { }; export const CloudLink: FunctionComponent = ({ application }) => { - const [isEntitledForCloudBackups, setIsEntitledForCloudBackups] = useState(false); - const [isFailedCloudBackupEmailMuted, setIsFailedCloudBackupEmailMuted] = useState(true); + const [isEntitledForCloudBackups, setIsEntitledForCloudBackups] = + useState(false); + const [isFailedCloudBackupEmailMuted, setIsFailedCloudBackupEmailMuted] = + useState(true); const [isLoading, setIsLoading] = useState(false); const loadIsFailedCloudBackupEmailMutedSetting = useCallback(async () => { @@ -98,12 +108,12 @@ export const CloudLink: FunctionComponent = ({ application }) => { A Plus or{' '} Pro subscription plan is required to enable Cloud Backups.{' '} - + Learn more . - + )}
= ({ application }) => {
{providerData.map(({ name }) => ( <> - + ))} diff --git a/app/assets/javascripts/preferences/panes/general-segments/Defaults.tsx b/app/assets/javascripts/preferences/panes/general-segments/Defaults.tsx index 077f9cf14..3b108879e 100644 --- a/app/assets/javascripts/preferences/panes/general-segments/Defaults.tsx +++ b/app/assets/javascripts/preferences/panes/general-segments/Defaults.tsx @@ -1,5 +1,4 @@ import { Dropdown, DropdownItem } from '@/components/Dropdown'; -import { IconType } from '@/components/Icon'; import { FeatureIdentifier, PrefKey } from '@standardnotes/snjs'; import { PreferencesGroup, @@ -27,31 +26,6 @@ type EditorOption = DropdownItem & { value: FeatureIdentifier | 'plain-editor'; }; -export const getIconAndTintForEditor = ( - identifier: FeatureIdentifier | undefined -): [IconType, number] => { - switch (identifier) { - case FeatureIdentifier.BoldEditor: - case FeatureIdentifier.PlusEditor: - return ['rich-text', 1]; - case FeatureIdentifier.MarkdownBasicEditor: - case FeatureIdentifier.MarkdownMathEditor: - case FeatureIdentifier.MarkdownMinimistEditor: - case FeatureIdentifier.MarkdownProEditor: - return ['markdown', 2]; - case FeatureIdentifier.TokenVaultEditor: - return ['authenticator', 6]; - case FeatureIdentifier.SheetsEditor: - return ['spreadsheets', 5]; - case FeatureIdentifier.TaskEditor: - return ['tasks', 3]; - case FeatureIdentifier.CodeEditor: - return ['code', 4]; - default: - return ['plain-text', 1]; - } -}; - const makeEditorDefault = ( application: WebApplication, component: SNComponent, @@ -103,7 +77,8 @@ export const Defaults: FunctionComponent = ({ application }) => { .componentsForArea(ComponentArea.Editor) .map((editor): EditorOption => { const identifier = editor.package_info.identifier; - const [iconType, tint] = getIconAndTintForEditor(identifier); + const [iconType, tint] = + application.iconsController.getIconAndTintForEditor(identifier); return { label: editor.name, diff --git a/app/assets/javascripts/preferences/panes/two-factor-auth/AuthAppInfoPopup.tsx b/app/assets/javascripts/preferences/panes/two-factor-auth/AuthAppInfoPopup.tsx index c9b731ebc..203783cfa 100644 --- a/app/assets/javascripts/preferences/panes/two-factor-auth/AuthAppInfoPopup.tsx +++ b/app/assets/javascripts/preferences/panes/two-factor-auth/AuthAppInfoPopup.tsx @@ -1,4 +1,4 @@ -import { Icon, IconType } from '@/components/Icon'; +import { Icon } from '@/components/Icon'; import { Disclosure, DisclosureButton, @@ -7,6 +7,7 @@ import { import { FunctionComponent } from 'preact'; import { MouseEventHandler } from 'react'; import { useState, useRef, useEffect } from 'preact/hooks'; +import { IconType } from '@standardnotes/snjs'; const DisclosureIconButton: FunctionComponent<{ className?: string; diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index 0e5477c57..f5b6dbd16 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -15,6 +15,7 @@ import { SNApplication, NoteGroupController, removeFromArray, + IconsController, } from '@standardnotes/snjs'; type WebServices = { @@ -39,6 +40,7 @@ export class WebApplication extends SNApplication { private webServices!: WebServices; public noteControllerGroup: NoteGroupController; private webEventObservers: WebEventObserver[] = []; + public iconsController: IconsController; constructor( deviceInterface: WebDeviceInterface, @@ -64,6 +66,7 @@ export class WebApplication extends SNApplication { ); deviceInterface.setApplication(this); this.noteControllerGroup = new NoteGroupController(this); + this.iconsController = new IconsController(); } /** @override */ @@ -76,6 +79,7 @@ export class WebApplication extends SNApplication { } this.webServices = {} as WebServices; this.noteControllerGroup.deinit(); + this.iconsController.deinit(); this.webEventObservers.length = 0; /** * Allow any pending renders to complete before destroying the global diff --git a/package.json b/package.json index 3d31f8f86..c06e5230d 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@reach/tooltip": "^0.16.2", "@standardnotes/components": "1.4.4", "@standardnotes/features": "1.26.1", - "@standardnotes/snjs": "2.44.3", + "@standardnotes/snjs": "2.45.0", "@standardnotes/settings": "^1.10.0", "@standardnotes/sncrypto-web": "1.6.0", "mobx": "^6.3.5", diff --git a/yarn.lock b/yarn.lock index eeebdbdd8..811745775 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2636,10 +2636,10 @@ resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.10.0.tgz#b46d4805c9a1cfb3fa3d9b3915daae9dd5661789" integrity sha512-FUy4RDI7nFnbOGAaX5wMvBz+6Yto5tXGXDAi7bnWALZByTIlN8bkFZ2CNk2skjpzeOxBjqhCRi+GRCcuMqZ70A== -"@standardnotes/settings@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.11.0.tgz#8bdb987a9ebb8b480ee9e32ad67c4e0ac7d9f0fe" - integrity sha512-4a4408m+afO00fsp/Pxcyx2N8BOWpvKHqv9u3PisKBy3xZTUdman7ah/KHPvUd7MFEYbY7frB/DoHN3tiokArQ== +"@standardnotes/settings@^1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.11.1.tgz#62e0df52820534c67041c99ed7f2c3a277158f39" + integrity sha512-uZChaTlIV63fYn7ODzVd/IB0nvrgyo/DwVaNgkjjHd3doGYqBMzzdfhs0RT0Ffpy0LOQhLpLBYqyJAryl1c4EA== "@standardnotes/sncrypto-common@^1.6.0": version "1.6.0" @@ -2655,16 +2655,16 @@ buffer "^6.0.3" libsodium-wrappers "^0.7.9" -"@standardnotes/snjs@2.44.3": - version "2.44.3" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.44.3.tgz#bb16aca691d24f2a7fea6f94a929f0a241ebcfc0" - integrity sha512-54rjz1s+pDdB4fRS69QE3DLNbebC+1DCw/+j5/2EOqdelj+/Ce7bQyiNxwYj4cqE0Z0zYEeJl7oAxVecOBCQZw== +"@standardnotes/snjs@2.45.0": + version "2.45.0" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.45.0.tgz#d123434b959d279af2ffe00acf2e9e6784cf497c" + integrity sha512-gTlOG3wd4zYaBeReypQiz+ASEnVCKaB8kWtKF61nkV9j3vFgYh3krsvdhOi6lMXBk+CijEefeLhrmooOtv08Xg== dependencies: "@standardnotes/auth" "^3.15.3" "@standardnotes/common" "^1.8.0" "@standardnotes/domain-events" "^2.20.1" "@standardnotes/features" "^1.26.1" - "@standardnotes/settings" "^1.11.0" + "@standardnotes/settings" "^1.11.1" "@standardnotes/sncrypto-common" "^1.6.0" "@svgr/babel-plugin-add-jsx-attribute@^5.4.0":