feat: add pref to disable note status updates (#1702)

This commit is contained in:
Aman Harwara
2022-09-30 20:34:56 +05:30
committed by GitHub
parent 0fa9f6d7b6
commit 08b70968f2
5 changed files with 149 additions and 39 deletions

View File

@@ -36,6 +36,7 @@ export enum PrefKey {
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
NewNoteTitleFormat = 'newNoteTitleFormat',
CustomNoteTitleFormat = 'customNoteTitleFormat',
UpdateSavingStatusIndicator = 'updateSavingStatusIndicator',
}
export enum NewNoteTitleFormat {
@@ -97,4 +98,5 @@ export type PrefValue = {
[PrefKey.CustomNoteTitleFormat]: string
[PrefKey.EditorLineHeight]: EditorLineHeight
[PrefKey.EditorFontSize]: EditorFontSize
[PrefKey.UpdateSavingStatusIndicator]: boolean
}

View File

@@ -1,6 +1,8 @@
import { ElementIds } from '@/Constants/ElementIDs'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import { classNames } from '@/Utils/ConcatenateClassNames'
import { useState } from 'react'
import { ReactNode, useState } from 'react'
import { IconType, PrefKey } from '@standardnotes/snjs'
import Icon from '../Icon/Icon'
export type NoteStatus = {
@@ -9,58 +11,131 @@ export type NoteStatus = {
desc?: string
}
const IndicatorWithTooltip = ({
className,
onClick,
onBlur,
icon,
isTooltipVisible,
children,
animateIcon = false,
}: {
className: string
onClick: () => void
onBlur: () => void
icon: IconType
isTooltipVisible: boolean
children: ReactNode
animateIcon?: boolean
}) => (
<div className="relative">
<button
className={classNames('peer flex h-5 w-5 items-center justify-center rounded-full', className)}
onClick={onClick}
onBlur={onBlur}
aria-describedby={ElementIds.NoteStatusTooltip}
>
<Icon className={animateIcon ? 'animate-spin' : ''} type={icon} size="small" />
<span className="sr-only">Note sync status</span>
</button>
<div
id={ElementIds.NoteStatusTooltip}
className={classNames(
isTooltipVisible ? '' : 'hidden',
'absolute top-full right-0 min-w-[90vw] translate-x-2 translate-y-1 select-none rounded border border-border bg-default py-1.5 px-3 text-left peer-hover:block peer-focus:block md:min-w-max',
)}
>
{children}
</div>
</div>
)
type Props = {
status: NoteStatus | undefined
syncTakingTooLong: boolean
updateSavingIndicator?: boolean
}
const NoteStatusIndicator = ({ status, syncTakingTooLong }: Props) => {
const [shouldShowTooltip, setShouldShowTooltip] = useState(false)
const NoteStatusIndicator = ({
status,
syncTakingTooLong,
updateSavingIndicator = PrefDefaults[PrefKey.UpdateSavingStatusIndicator],
}: Props) => {
const [isTooltipVisible, setIsTooltipVisible] = useState(false)
if (!status) {
const onClick = () => setIsTooltipVisible((show) => !show)
const onBlur = () => setIsTooltipVisible(false)
if (updateSavingIndicator && !status) {
return null
}
return (
<div className="relative">
<button
if (status && status.type === 'error') {
return (
<IndicatorWithTooltip
className="bg-danger text-danger-contrast"
onClick={onClick}
onBlur={onBlur}
icon="warning"
isTooltipVisible={isTooltipVisible}
>
<div className="text-sm font-bold text-danger">{status.message}</div>
{status.desc && <div className="mt-0.5">{status.desc}</div>}
</IndicatorWithTooltip>
)
}
if (syncTakingTooLong) {
return (
<IndicatorWithTooltip
className="bg-warning text-warning-contrast"
onClick={onClick}
onBlur={onBlur}
icon={status && status.type === 'saving' ? 'sync' : 'warning'}
isTooltipVisible={isTooltipVisible}
>
{status ? (
<>
<div className="text-sm font-bold text-warning">{status.message}</div>
{status.desc && <div className="mt-0.5">{status.desc}</div>}
</>
) : (
<div className="text-sm font-bold text-warning">Sync taking too long</div>
)}
</IndicatorWithTooltip>
)
}
if (updateSavingIndicator && status) {
return (
<IndicatorWithTooltip
className={classNames(
'peer flex h-5 w-5 items-center justify-center rounded-full',
status.type === 'saving' && 'bg-contrast',
status.type === 'saved' && 'bg-success text-success-contrast',
status.type === 'error' && 'bg-danger text-danger-contrast',
syncTakingTooLong && 'bg-warning text-warning-contrast',
)}
onClick={() => setShouldShowTooltip((show) => !show)}
onBlur={() => setShouldShowTooltip(false)}
aria-describedby={ElementIds.NoteStatusTooltip}
onClick={onClick}
onBlur={onBlur}
icon={status.type === 'saving' ? 'sync' : 'check'}
animateIcon={status.type === 'saving'}
isTooltipVisible={isTooltipVisible}
>
<Icon
className={status.type === 'saving' ? 'animate-spin' : ''}
type={status.type === 'saved' ? 'check' : status.type === 'error' ? 'warning' : 'sync'}
size="small"
/>
<span className="sr-only">Note sync status</span>
</button>
<div
id={ElementIds.NoteStatusTooltip}
className={classNames(
shouldShowTooltip ? '' : 'hidden',
'absolute top-full right-0 min-w-max translate-x-2 translate-y-1 select-none rounded border border-border bg-default py-1.5 px-3 text-left peer-hover:block peer-focus:block',
)}
>
<div
className={classNames(
'text-sm font-bold',
status.type === 'error' && 'text-danger',
syncTakingTooLong && 'text-warning',
)}
>
{status.message}
</div>
<div className="text-sm font-bold">{status.message}</div>
{status.desc && <div className="mt-0.5">{status.desc}</div>}
</div>
</div>
</IndicatorWithTooltip>
)
}
return (
<IndicatorWithTooltip
className="bg-contrast text-passive-1"
onClick={onClick}
onBlur={onBlur}
icon="info"
isTooltipVisible={isTooltipVisible}
>
<div className="text-sm font-bold">Note status updates are disabled</div>
<div className="mt-0.5">They can be re-enabled in the Preferences under General &gt; Tools</div>
</IndicatorWithTooltip>
)
}

View File

@@ -87,6 +87,7 @@ type State = {
monospaceFont?: boolean
lineHeight?: EditorLineHeight
fontSize?: EditorFontSize
updateSavingIndicator?: boolean
}
const PlaintextFontSizeMapping: Record<EditorFontSize, string> = {
@@ -718,6 +719,11 @@ class NoteView extends PureComponent<NoteViewProps, State> {
const fontSize = this.application.getPreference(PrefKey.EditorFontSize, PrefDefaults[PrefKey.EditorFontSize])
const updateSavingIndicator = this.application.getPreference(
PrefKey.UpdateSavingStatusIndicator,
PrefDefaults[PrefKey.UpdateSavingStatusIndicator],
)
await this.reloadSpellcheck()
this.setState({
@@ -725,6 +731,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
marginResizersEnabled,
lineHeight,
fontSize,
updateSavingIndicator,
})
reloadFont(monospaceFont)
@@ -984,7 +991,11 @@ class NoteView extends PureComponent<NoteViewProps, State> {
autoComplete="off"
/>
</div>
<NoteStatusIndicator status={this.state.noteStatus} syncTakingTooLong={this.state.syncTakingTooLong} />
<NoteStatusIndicator
status={this.state.noteStatus}
syncTakingTooLong={this.state.syncTakingTooLong}
updateSavingIndicator={this.state.updateSavingIndicator}
/>
</div>
{!this.state.shouldStickyHeader && (
<div className="flex items-center gap-3">

View File

@@ -7,6 +7,7 @@ import { FunctionComponent, useState } from 'react'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
import { PrefDefaults } from '@/Constants/PrefDefaults'
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
type Props = {
application: WebApplication
@@ -22,6 +23,15 @@ const Tools: FunctionComponent<Props> = ({ application }: Props) => {
application.setPreference(PrefKey.EditorResizersEnabled, !marginResizers).catch(console.error)
}
const [updateSavingIndicator, setUpdateSavingIndicator] = useState(() =>
application.getPreference(PrefKey.UpdateSavingStatusIndicator, PrefDefaults[PrefKey.UpdateSavingStatusIndicator]),
)
const toggleSavingIndicatorUpdates = () => {
setUpdateSavingIndicator(!updateSavingIndicator)
application.setPreference(PrefKey.UpdateSavingStatusIndicator, !updateSavingIndicator).catch(console.error)
}
return (
<PreferencesGroup>
<PreferencesSegment>
@@ -34,6 +44,17 @@ const Tools: FunctionComponent<Props> = ({ application }: Props) => {
</div>
<Switch onChange={toggleMarginResizers} checked={marginResizers} />
</div>
<HorizontalSeparator classes="my-4" />
<div className="flex items-center justify-between">
<div className="flex flex-col">
<Subtitle>Show note saving status while editing</Subtitle>
<Text>
Control whether the animated saving status is shown while editing. Error statuses are always shown
regardless of preference.
</Text>
</div>
<Switch onChange={toggleSavingIndicatorUpdates} checked={updateSavingIndicator} />
</div>
</div>
</PreferencesSegment>
</PreferencesGroup>

View File

@@ -26,4 +26,5 @@ export const PrefDefaults = {
[PrefKey.NoteAddToParentFolders]: true,
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
[PrefKey.UpdateSavingStatusIndicator]: true,
} as const