feat: Added "Keyboard shortcuts" help dialog. Can be opened by pressing Shift + ?

This commit is contained in:
Aman Harwara
2024-01-27 15:25:49 +05:30
parent 289849724a
commit ff3c45ba35
27 changed files with 312 additions and 27 deletions

View File

@@ -9,7 +9,7 @@ export function platformFromString(string: string) {
'windows-web': Platform.WindowsWeb,
'windows-desktop': Platform.WindowsDesktop,
'ios-web': Platform.Ios,
android: Platform.Android,
'android-web': Platform.Android,
}
return map[string]
}

View File

@@ -1,7 +1,10 @@
import { KeyboardCommand } from './KeyboardCommands'
import { KeyboardShortcutCategory } from './KeyboardShortcut'
export type KeyboardCommandHandler = {
command: KeyboardCommand
category?: KeyboardShortcutCategory
description?: string
onKeyDown?: (event: KeyboardEvent, data?: unknown) => boolean | void
onKeyUp?: (event: KeyboardEvent, data?: unknown) => boolean | void
element?: HTMLElement

View File

@@ -39,3 +39,5 @@ export const SUPER_EXPORT_MARKDOWN = createKeyboardCommand('SUPER_EXPORT_MARKDOW
export const OPEN_PREFERENCES_COMMAND = createKeyboardCommand('OPEN_PREFERENCES_COMMAND')
export const CHANGE_EDITOR_WIDTH_COMMAND = createKeyboardCommand('CHANGE_EDITOR_WIDTH_COMMAND')
export const TOGGLE_KEYBOARD_SHORTCUTS_MODAL = createKeyboardCommand('TOGGLE_KEYBOARD_SHORTCUTS_MODAL')

View File

@@ -1,3 +1,6 @@
import { Platform } from '@standardnotes/models'
import { isMacPlatform } from './platformCheck'
export enum KeyboardModifier {
Shift = 'Shift',
Ctrl = 'Control',
@@ -5,3 +8,7 @@ export enum KeyboardModifier {
Meta = 'Meta',
Alt = 'Alt',
}
export function getPrimaryModifier(platform: Platform): KeyboardModifier {
return isMacPlatform(platform) ? KeyboardModifier.Meta : KeyboardModifier.Ctrl
}

View File

@@ -4,7 +4,7 @@ import { KeyboardCommand } from './KeyboardCommands'
import { KeyboardKeyEvent } from './KeyboardKeyEvent'
import { KeyboardModifier } from './KeyboardModifier'
import { KeyboardCommandHandler } from './KeyboardCommandHandler'
import { KeyboardShortcut, PlatformedKeyboardShortcut } from './KeyboardShortcut'
import { KeyboardShortcut, KeyboardShortcutHelpItem, PlatformedKeyboardShortcut } from './KeyboardShortcut'
import { getKeyboardShortcuts } from './getKeyboardShortcuts'
export class KeyboardService {
@@ -12,6 +12,8 @@ export class KeyboardService {
private commandHandlers = new Set<KeyboardCommandHandler>()
private commandMap = new Map<KeyboardCommand, KeyboardShortcut>()
private keyboardShortcutHelpItems = new Set<KeyboardShortcutHelpItem>()
constructor(
private platform: Platform,
environment: Environment,
@@ -190,10 +192,18 @@ export class KeyboardService {
addCommandHandler(observer: KeyboardCommandHandler): () => void {
this.commandHandlers.add(observer)
const helpItem = this.getKeyboardShortcutHelpItemForHandler(observer)
if (helpItem) {
this.keyboardShortcutHelpItems.add(helpItem)
}
return () => {
observer.onKeyDown = undefined
observer.onKeyDown = undefined
this.commandHandlers.delete(observer)
if (helpItem) {
this.keyboardShortcutHelpItems.delete(helpItem)
}
}
}
@@ -217,4 +227,48 @@ export class KeyboardService {
...shortcut,
}
}
getKeyboardShortcutHelpItemForHandler(handler: KeyboardCommandHandler): KeyboardShortcutHelpItem | undefined {
const shortcut = this.keyboardShortcutForCommand(handler.command)
if (!shortcut || !handler.category || !handler.description) {
return undefined
}
return {
...shortcut,
category: handler.category,
description: handler.description,
}
}
/**
* Register help item for a keyboard shortcut that is handled outside of the KeyboardService,
* for example by a library like Lexical.
*/
registerExternalKeyboardShortcutHelpItem(item: KeyboardShortcutHelpItem): () => void {
this.keyboardShortcutHelpItems.add(item)
return () => {
this.keyboardShortcutHelpItems.delete(item)
}
}
/**
* Register help item for a keyboard shortcut that is handled outside of the KeyboardService,
* for example by a library like Lexical.
*/
registerExternalKeyboardShortcutHelpItems(items: KeyboardShortcutHelpItem[]): () => void {
const disposers = items.map((item) => this.registerExternalKeyboardShortcutHelpItem(item))
return () => {
for (const disposer of disposers) {
disposer()
}
}
}
getRegisteredKeyboardShorcutHelpItems(): KeyboardShortcutHelpItem[] {
return Array.from(this.keyboardShortcutHelpItems)
}
}

View File

@@ -18,3 +18,10 @@ export type KeyboardShortcut = {
export type PlatformedKeyboardShortcut = KeyboardShortcut & {
platform: Platform
}
export type KeyboardShortcutCategory = 'General' | 'Notes list' | 'Current note' | 'Super notes' | 'Formatting'
export type KeyboardShortcutHelpItem = Omit<PlatformedKeyboardShortcut, 'command'> & {
category: KeyboardShortcutCategory
description: string
}

View File

@@ -1,5 +1,4 @@
import { Environment, Platform } from '@standardnotes/models'
import { isMacPlatform } from './platformCheck'
import {
CREATE_NEW_NOTE_KEYBOARD_COMMAND,
TOGGLE_LIST_PANE_KEYBOARD_COMMAND,
@@ -31,15 +30,14 @@ import {
SUPER_SEARCH_TOGGLE_REPLACE_MODE,
CHANGE_EDITOR_WIDTH_COMMAND,
SUPER_TOGGLE_TOOLBAR,
TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
} from './KeyboardCommands'
import { KeyboardKey } from './KeyboardKey'
import { KeyboardModifier } from './KeyboardModifier'
import { KeyboardModifier, getPrimaryModifier } from './KeyboardModifier'
import { KeyboardShortcut } from './KeyboardShortcut'
export function getKeyboardShortcuts(platform: Platform, _environment: Environment): KeyboardShortcut[] {
const isMac = isMacPlatform(platform)
const primaryModifier = isMac ? KeyboardModifier.Meta : KeyboardModifier.Ctrl
const primaryModifier = getPrimaryModifier(platform)
return [
{
@@ -195,5 +193,11 @@ export function getKeyboardShortcuts(platform: Platform, _environment: Environme
modifiers: [primaryModifier, KeyboardModifier.Shift],
preventDefault: true,
},
{
command: TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
key: '?',
preventDefault: true,
modifiers: [KeyboardModifier.Shift],
},
]
}

View File

@@ -0,0 +1,20 @@
export function keyboardCharacterForKeyOrCode(keyOrCode: string) {
if (keyOrCode.startsWith('Digit')) {
return keyOrCode.replace('Digit', '')
}
if (keyOrCode.startsWith('Key')) {
return keyOrCode.replace('Key', '')
}
switch (keyOrCode) {
case 'ArrowDown':
return '↓'
case 'ArrowUp':
return '↑'
case 'ArrowLeft':
return '←'
case 'ArrowRight':
return '→'
default:
return keyOrCode
}
}

View File

@@ -10,6 +10,7 @@ export * from './Keyboard/KeyboardCommands'
export * from './Keyboard/platformCheck'
export * from './Keyboard/KeyboardKey'
export * from './Keyboard/KeyboardModifier'
export * from './Keyboard/keyboardCharacterForKey'
export * from './Keyboard/keyboardCharacterForModifier'
export * from './Keyboard/keyboardStringForShortcut'
export * from './Route/Params/DemoParams'

View File

@@ -13,6 +13,8 @@ import Spinner from '@/Components/Spinner/Spinner'
import { MenuItemIconSize } from '@/Constants/TailwindClassNames'
import { useApplication } from '../ApplicationProvider'
import MenuSection from '../Menu/MenuSection'
import { TOGGLE_KEYBOARD_SHORTCUTS_MODAL, isMobilePlatform } from '@standardnotes/ui-services'
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
type Props = {
mainApplicationGroup: WebApplicationGroup
@@ -90,6 +92,10 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
const CREATE_ACCOUNT_INDEX = 1
const SWITCHER_INDEX = 0
const keyboardShortcutsHelpShortcut = useMemo(() => {
return application.keyboardService.keyboardShortcutForCommand(TOGGLE_KEYBOARD_SHORTCUTS_MODAL)
}, [application.keyboardService])
return (
<>
<div className="mb-1 mt-1 hidden items-center justify-between px-4 md:flex md:px-3">
@@ -187,6 +193,19 @@ const GeneralAccountMenu: FunctionComponent<Props> = ({ setMenuPane, closeMenu,
</div>
<span className="text-neutral">v{application.version}</span>
</MenuItem>
{!isMobilePlatform(application.platform) && (
<MenuItem
onClick={() => {
application.keyboardService.triggerCommand(TOGGLE_KEYBOARD_SHORTCUTS_MODAL)
}}
>
<Icon type="keyboard" className={iconClassName} />
Keyboard shortcuts
{keyboardShortcutsHelpShortcut && (
<KeyboardShortcutIndicator shortcut={keyboardShortcutsHelpShortcut} className="ml-auto" />
)}
</MenuItem>
)}
</MenuSection>
{user ? (
<MenuSection>

View File

@@ -31,6 +31,7 @@ import ImportModal from '../ImportModal/ImportModal'
import IosKeyboardClose from '../IosKeyboardClose/IosKeyboardClose'
import EditorWidthSelectionModalWrapper from '../EditorWidthSelectionModal/EditorWidthSelectionModal'
import { ProtectionEvent } from '@standardnotes/services'
import KeyboardShortcutsModal from '../KeyboardShortcutsHelpModal/KeyboardShortcutsHelpModal'
type Props = {
application: WebApplication
@@ -267,6 +268,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
<EditorWidthSelectionModalWrapper />
<ConfirmDeleteAccountContainer application={application} />
<ImportModal importModalController={application.importModalController} />
<KeyboardShortcutsModal keyboardService={application.keyboardService} />
</>
{application.routeService.isDotOrg && <DotOrgNotice />}
{isIOS() && <IosKeyboardClose />}

View File

@@ -57,6 +57,8 @@ const ChangeEditorButton: FunctionComponent<Props> = ({ noteViewController, onCl
useEffect(() => {
return application.keyboardService.addCommandHandler({
command: CHANGE_EDITOR_COMMAND,
category: 'Current note',
description: 'Change note type',
onKeyDown: () => {
void toggleMenu()
},

View File

@@ -178,6 +178,8 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
return application.keyboardService.addCommandHandlers([
{
command: CREATE_NEW_NOTE_KEYBOARD_COMMAND,
category: 'General',
description: 'Create new note',
onKeyDown: (event) => {
event.preventDefault()
void addNewItem()
@@ -185,6 +187,8 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
},
{
command: NEXT_LIST_ITEM_KEYBOARD_COMMAND,
category: 'Notes list',
description: 'Go to next item',
elements: [document.body, ...(searchBarElement ? [searchBarElement] : [])],
onKeyDown: () => {
if (searchBarElement === document.activeElement) {
@@ -198,6 +202,8 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
},
{
command: PREVIOUS_LIST_ITEM_KEYBOARD_COMMAND,
category: 'Notes list',
description: 'Go to previous item',
element: document.body,
onKeyDown: () => {
if (shouldUseTableView) {
@@ -208,6 +214,8 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
},
{
command: SEARCH_KEYBOARD_COMMAND,
category: 'General',
description: 'Toggle global search',
onKeyDown: (event) => {
if (searchBarElement) {
event.preventDefault()
@@ -225,6 +233,8 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
},
{
command: SELECT_ALL_ITEMS_KEYBOARD_COMMAND,
category: 'General',
description: 'Select all items',
onKeyDown: (event) => {
const isTargetInsideContentList = (event.target as HTMLElement).closest(`#${ElementIds.ContentList}`)

View File

@@ -180,6 +180,8 @@ const EditorWidthSelectionModalWrapper = () => {
useEffect(() => {
return application.keyboardService.addCommandHandler({
command: CHANGE_EDITOR_WIDTH_COMMAND,
category: 'Current note',
description: 'Change editor width',
onKeyDown: (_, data) => {
if (typeof data === 'boolean' && data) {
setIsGlobal(data)

View File

@@ -25,6 +25,8 @@ const QuickSettingsButton = ({ application, isMobileNavigation = false }: Props)
useEffect(() => {
return commandService.addCommandHandler({
command: TOGGLE_DARK_MODE_COMMAND,
category: 'General',
description: 'Toggle dark mode',
onKeyDown: () => {
void application.componentManager.toggleTheme(new UIFeature(GetDarkThemeFeature()))
},

View File

@@ -1,31 +1,31 @@
import { classNames } from '@standardnotes/snjs'
import {
PlatformedKeyboardShortcut,
keyboardCharacterForModifier,
isMacPlatform,
isMobilePlatform,
keyboardCharacterForKeyOrCode,
} from '@standardnotes/ui-services'
import { useMemo } from 'react'
type Props = {
shortcut: PlatformedKeyboardShortcut
shortcut: Omit<PlatformedKeyboardShortcut, 'command'>
small?: boolean
dimmed?: boolean
className?: string
}
export const KeyboardShortcutIndicator = ({ shortcut, className }: Props) => {
const addPluses = !isMacPlatform(shortcut.platform)
const spacingClass = addPluses ? '' : 'ml-0.5'
export const KeyboardShortcutIndicator = ({ shortcut, small = true, dimmed = true, className }: Props) => {
const keys = useMemo(() => {
const modifiers = shortcut.modifiers || []
const primaryKey = (shortcut.key || '').toUpperCase()
const primaryKey = shortcut.key
? keyboardCharacterForKeyOrCode(shortcut.key)
: shortcut.code
? keyboardCharacterForKeyOrCode(shortcut.code)
: undefined
const results: string[] = []
modifiers.forEach((modifier, index) => {
modifiers.forEach((modifier) => {
results.push(keyboardCharacterForModifier(modifier, shortcut.platform))
if (addPluses && (primaryKey || index !== modifiers.length - 1)) {
results.push('+')
}
})
if (primaryKey) {
@@ -33,19 +33,25 @@ export const KeyboardShortcutIndicator = ({ shortcut, className }: Props) => {
}
return results
}, [shortcut, addPluses])
}, [shortcut])
if (isMobilePlatform(shortcut.platform)) {
return null
}
return (
<div className={`keyboard-shortcut-indicator flex opacity-[0.35] ${className}`}>
<div className={classNames('flex items-center gap-1', dimmed && 'opacity-70', className)}>
{keys.map((key, index) => {
return (
<div className={index !== 0 ? spacingClass : ''} key={index}>
<kbd
className={classNames(
'rounded border-[0.5px] border-passive-3 bg-default p-1 text-center font-sans capitalize leading-none text-text shadow-[var(--tw-shadow-color)_0px_2px_0px_0px] shadow-passive-3',
small ? 'text-[length:0.65rem]' : 'text-xs',
)}
key={index}
>
{key}
</div>
</kbd>
)
})}
</div>

View File

@@ -0,0 +1,78 @@
import { useCallback, useEffect, useState } from 'react'
import Modal from '../Modal/Modal'
import ModalOverlay from '../Modal/ModalOverlay'
import {
KeyboardService,
KeyboardShortcutCategory,
KeyboardShortcutHelpItem,
TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
} from '@standardnotes/ui-services'
import { observer } from 'mobx-react-lite'
import { KeyboardShortcutIndicator } from '../KeyboardShortcutIndicator/KeyboardShortcutIndicator'
type GroupedItems = {
[category in KeyboardShortcutCategory]: KeyboardShortcutHelpItem[]
}
const createGroupedItems = (items: KeyboardShortcutHelpItem[]): GroupedItems => {
const groupedItems: GroupedItems = {
'Current note': [],
Formatting: [],
'Super notes': [],
'Notes list': [],
General: [],
}
return items.reduce((acc, item) => {
acc[item.category].push(item)
return acc
}, groupedItems)
}
const Item = ({ item }: { item: KeyboardShortcutHelpItem }) => {
return (
<div className="flex items-center gap-2 px-4 py-2.5">
<div>{item.description}</div>
<KeyboardShortcutIndicator className="ml-auto" shortcut={item} small={false} dimmed={false} />
</div>
)
}
const KeyboardShortcutsModal = ({ keyboardService }: { keyboardService: KeyboardService }) => {
const [isOpen, setIsOpen] = useState(false)
const [items, setItems] = useState(() => createGroupedItems(keyboardService.getRegisteredKeyboardShorcutHelpItems()))
const close = useCallback(() => {
setIsOpen(false)
}, [])
useEffect(() => {
return keyboardService.addCommandHandler({
command: TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
description: 'Toggle keyboard shortcuts help',
onKeyDown: () => {
setItems(createGroupedItems(keyboardService.getRegisteredKeyboardShorcutHelpItems()))
setIsOpen((open) => !open)
},
})
}, [keyboardService])
return (
<ModalOverlay isOpen={isOpen} close={close}>
<Modal title="Keyboard shortcuts" close={close}>
{Object.entries(items).map(
([category, items]) =>
items.length > 0 && (
<div key={category}>
<div className="p-4 pb-0.5 pt-4 text-base font-semibold capitalize">{category}</div>
{items.map((item, index) => (
<Item item={item} key={index} />
))}
</div>
),
)}
</Modal>
</ModalOverlay>
)
}
export default observer(KeyboardShortcutsModal)

View File

@@ -60,6 +60,8 @@ const LinkedItemBubblesContainer = ({
useEffect(() => {
return commandService.addCommandHandler({
command: FOCUS_TAGS_INPUT_COMMAND,
category: 'Current note',
description: 'Link tags, notes, files',
onKeyDown: () => {
const input = document.getElementById(ElementIds.ItemLinkAutocompleteInput)
if (input) {

View File

@@ -15,6 +15,8 @@ const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperProps> = (
useEffect(() => {
return commandService.addCommandHandler({
command: OPEN_PREFERENCES_COMMAND,
category: 'General',
description: 'Open preferences',
onKeyDown: () => application.preferencesController.openPreferences(),
})
}, [commandService, application])

View File

@@ -38,6 +38,8 @@ export const SearchPlugin = () => {
return application.keyboardService.addCommandHandlers([
{
command: SUPER_TOGGLE_SEARCH,
category: 'Super notes',
description: 'Search in current note',
onKeyDown: (event) => {
if (!isFocusInEditor()) {
return
@@ -50,6 +52,8 @@ export const SearchPlugin = () => {
},
{
command: SUPER_SEARCH_TOGGLE_REPLACE_MODE,
category: 'Super notes',
description: 'Search and replace in current note',
onKeyDown: (event) => {
if (!isFocusInEditor()) {
return
@@ -72,6 +76,8 @@ export const SearchPlugin = () => {
},
{
command: SUPER_SEARCH_NEXT_RESULT,
category: 'Super notes',
description: 'Go to next search result',
onKeyDown(event) {
if (!isFocusInEditor()) {
return
@@ -85,6 +91,8 @@ export const SearchPlugin = () => {
},
{
command: SUPER_SEARCH_PREVIOUS_RESULT,
category: 'Super notes',
description: 'Go to previous search result',
onKeyDown(event) {
if (!isFocusInEditor()) {
return

View File

@@ -553,6 +553,8 @@ const ToolbarPlugin = () => {
useEffect(() => {
return application.keyboardService.addCommandHandler({
command: SUPER_TOGGLE_TOOLBAR,
category: 'Super notes',
description: 'Toggle Super note toolbar',
onKeyDown(event) {
if (isMobile) {
return

View File

@@ -28,7 +28,7 @@ import {
ChangeEditorFunction,
} from './Plugins/ChangeContentCallback/ChangeContentCallback'
import { useCommandService } from '@/Components/CommandProvider'
import { SUPER_SHOW_MARKDOWN_PREVIEW } from '@standardnotes/ui-services'
import { SUPER_SHOW_MARKDOWN_PREVIEW, getPrimaryModifier } from '@standardnotes/ui-services'
import { SuperNoteMarkdownPreview } from './SuperNoteMarkdownPreview'
import GetMarkdownPlugin, { GetMarkdownPluginInterface } from './Plugins/GetMarkdownPlugin/GetMarkdownPlugin'
import { useResponsiveEditorFontSize } from '@/Utils/getPlaintextFontSize'
@@ -83,10 +83,48 @@ export const SuperEditor: FunctionComponent<Props> = ({
useEffect(() => {
return commandService.addCommandHandler({
command: SUPER_SHOW_MARKDOWN_PREVIEW,
category: 'Super notes',
description: 'Show markdown preview for current note',
onKeyDown: () => setShowMarkdownPreview(true),
})
}, [commandService])
useEffect(() => {
const platform = application.platform
const primaryModifier = getPrimaryModifier(application.platform)
return commandService.registerExternalKeyboardShortcutHelpItems([
{
key: 'b',
modifiers: [primaryModifier],
description: 'Bold',
category: 'Formatting',
platform: platform,
},
{
key: 'i',
modifiers: [primaryModifier],
description: 'Italic',
category: 'Formatting',
platform: platform,
},
{
key: 'u',
modifiers: [primaryModifier],
description: 'Underline',
category: 'Formatting',
platform: platform,
},
{
key: 'k',
modifiers: [primaryModifier],
description: 'Link',
category: 'Formatting',
platform: platform,
},
])
}, [application.platform, commandService])
const closeMarkdownPreview = useCallback(() => {
setShowMarkdownPreview(false)
}, [])

View File

@@ -189,6 +189,8 @@ export class NavigationController
this.disposers.push(
this.keyboardService.addCommandHandler({
command: CREATE_NEW_TAG_COMMAND,
category: 'General',
description: 'Create new tag',
onKeyDown: () => {
this.createNewTemplate()
},

View File

@@ -27,6 +27,8 @@ export class HistoryModalController extends AbstractViewController {
this.disposers.push(
keyboardService.addCommandHandler({
command: OPEN_NOTE_HISTORY_COMMAND,
category: 'Current note',
description: 'Open note history',
onKeyDown: () => {
this.openModal(notesController.firstSelectedNote)
return true

View File

@@ -90,12 +90,16 @@ export class NotesController
this.disposers.push(
this.keyboardService.addCommandHandler({
command: PIN_NOTE_COMMAND,
category: 'Current note',
description: 'Pin current note',
onKeyDown: () => {
this.togglePinSelectedNotes()
},
}),
this.keyboardService.addCommandHandler({
command: STAR_NOTE_COMMAND,
category: 'Current note',
description: 'Star current note',
onKeyDown: () => {
this.toggleStarSelectedNotes()
},

View File

@@ -102,6 +102,8 @@ export class PaneController extends AbstractViewController implements InternalEv
this.disposers.push(
keyboardService.addCommandHandler({
command: TOGGLE_FOCUS_MODE_COMMAND,
category: 'General',
description: 'Toggle focus mode',
onKeyDown: (event) => {
event.preventDefault()
this.setFocusModeEnabled(!this.focusModeEnabled)
@@ -110,6 +112,8 @@ export class PaneController extends AbstractViewController implements InternalEv
}),
keyboardService.addCommandHandler({
command: TOGGLE_LIST_PANE_KEYBOARD_COMMAND,
category: 'General',
description: 'Toggle notes panel',
onKeyDown: (event) => {
event.preventDefault()
this.toggleListPane()
@@ -117,6 +121,8 @@ export class PaneController extends AbstractViewController implements InternalEv
}),
keyboardService.addCommandHandler({
command: TOGGLE_NAVIGATION_PANE_KEYBOARD_COMMAND,
category: 'General',
description: 'Toggle tags panel',
onKeyDown: (event) => {
event.preventDefault()
this.toggleNavigationPane()

View File

@@ -2,7 +2,7 @@ import { DeviceInterface, MobileDeviceInterface, Platform, platformFromString }
import { IsDesktopPlatform, IsWebPlatform } from '@/Constants/Version'
import { EMAIL_REGEX } from '../Constants/Constants'
import { MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
import { isIOS } from '@standardnotes/ui-services'
import { isAndroid, isIOS } from '@standardnotes/ui-services'
declare const process: {
env: {
@@ -16,9 +16,9 @@ export function getPlatformString() {
try {
const platform = navigator.platform.toLowerCase()
let trimmed = ''
if (platform.includes('iphone')) {
if (platform.includes('iphone') || isIOS()) {
trimmed = 'ios'
} else if (platform.includes('android')) {
} else if (platform.includes('android') || isAndroid()) {
trimmed = 'android'
} else if (platform.includes('mac')) {
trimmed = 'mac'