feat: Added "New Note Defaults" options to Preferences > General

This commit is contained in:
Aman Harwara
2023-10-11 22:23:25 +05:30
parent 6065e4e16b
commit 91c2e0dce2
3 changed files with 193 additions and 2 deletions

View File

@@ -194,7 +194,7 @@ const NewNotePreferences: FunctionComponent<Props> = ({
<Dropdown
disabled={disabled}
fullWidth={true}
label="Select the default note type"
label="Select the format for the note title"
items={NoteTitleFormatOptions}
value={newNoteTitleFormat}
onChange={setNewNoteTitleFormatChange}
@@ -207,7 +207,7 @@ const NewNotePreferences: FunctionComponent<Props> = ({
<input
disabled={disabled}
className={classNames(
'w-full min-w-55 rounded border border-solid border-passive-3 bg-default md:translucent-ui:bg-transparent px-2 py-1.5 text-sm',
'w-full min-w-55 rounded border border-solid border-passive-3 bg-default px-2 py-1.5 text-sm md:translucent-ui:bg-transparent',
'focus-within:ring-2 focus-within:ring-info',
)}
placeholder="e.g. YYYY-MM-DD"

View File

@@ -10,6 +10,7 @@ import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
import Persistence from './Persistence'
import SmartViews from './SmartViews/SmartViews'
import Moments from './Moments'
import NewNoteDefaults from './NewNoteDefaults'
type Props = {
application: WebApplication
@@ -20,6 +21,7 @@ const General: FunctionComponent<Props> = ({ application, extensionsLatestVersio
<PreferencesPane>
<Persistence application={application} />
<Defaults application={application} />
<NewNoteDefaults />
<Tools application={application} />
<SmartViews application={application} featuresController={application.featuresController} />
<Moments application={application} />

View File

@@ -0,0 +1,189 @@
import Dropdown from '@/Components/Dropdown/Dropdown'
import { Subtitle, Title } from '../../PreferencesComponents/Content'
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
import { ChangeEventHandler, useCallback, useEffect, useRef, useState } from 'react'
import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
import { useApplication } from '@/Components/ApplicationProvider'
import { EditorOption, getDropdownItemsForAllEditors } from '@/Utils/DropdownItemsForEditors'
import {
FeatureStatus,
NativeFeatureIdentifier,
NewNoteTitleFormat,
PrefDefaults,
PrefKey,
Uuid,
classNames,
} from '@standardnotes/snjs'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { NoteTitleFormatOptions } from '@/Components/ContentListView/Header/NoteTitleFormatOptions'
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
import { ErrorBoundary } from '@/Utils/ErrorBoundary'
import { getDayjsFormattedString } from '@/Utils/GetDayjsFormattedString'
const PrefChangeDebounceTimeInMs = 25
const HelpPageUrl = 'https://day.js.org/docs/en/display/format#list-of-all-available-formats'
const NewNoteDefaults = () => {
const application = useApplication()
const premiumModal = usePremiumModal()
const [editorItems, setEditorItems] = useState<DropdownItem[]>([])
useEffect(() => {
setEditorItems(getDropdownItemsForAllEditors(application))
}, [application])
const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<string>(
NativeFeatureIdentifier.TYPES.PlainEditor,
)
const [newNoteTitleFormat, setNewNoteTitleFormat] = useState<NewNoteTitleFormat>(
NewNoteTitleFormat.CurrentDateAndTime,
)
const [customNoteTitleFormat, setCustomNoteTitleFormat] = useState('')
const reloadPreferences = useCallback(() => {
const globalDefault = application.componentManager.getDefaultEditorIdentifier()
setDefaultEditorIdentifier(globalDefault)
setNewNoteTitleFormat(
application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]),
)
setCustomNoteTitleFormat(
application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat]),
)
}, [application])
useEffect(() => {
void reloadPreferences()
}, [reloadPreferences])
const selectEditorForNewNoteDefault = useCallback(
(value: EditorOption['value']) => {
let identifier: NativeFeatureIdentifier | Uuid | undefined = undefined
const feature = NativeFeatureIdentifier.create(value)
if (!feature.isFailed()) {
identifier = feature.getValue()
} else {
const thirdPartyEditor = application.componentManager.findComponentWithPackageIdentifier(value)
if (thirdPartyEditor) {
identifier = Uuid.create(thirdPartyEditor.uuid).getValue()
}
}
if (!identifier) {
return
}
if (application.features.getFeatureStatus(identifier) !== FeatureStatus.Entitled) {
const editorItem = editorItems.find((item) => item.value === value)
if (editorItem) {
premiumModal.activate(editorItem.label)
}
return
}
setDefaultEditorIdentifier(value)
void application.setPreference(PrefKey.DefaultEditorIdentifier, value)
},
[application, editorItems, premiumModal],
)
const setNewNoteTitleFormatChange = useCallback(
(value: string) => {
setNewNoteTitleFormat(value as NewNoteTitleFormat)
void application.setPreference(PrefKey.NewNoteTitleFormat, value as NewNoteTitleFormat)
},
[application],
)
const debounceTimeoutRef = useRef<number>()
const handleCustomFormatInputChange: ChangeEventHandler<HTMLInputElement> = (event) => {
const newFormat = event.currentTarget.value
setCustomNoteTitleFormat(newFormat)
if (debounceTimeoutRef.current) {
clearTimeout(debounceTimeoutRef.current)
}
debounceTimeoutRef.current = window.setTimeout(async () => {
void application.setPreference(PrefKey.CustomNoteTitleFormat, newFormat)
}, PrefChangeDebounceTimeInMs)
}
return (
<PreferencesGroup>
<PreferencesSegment>
<Title>New Note Defaults</Title>
<div className="mt-2">
<div>
<Subtitle>Note Type</Subtitle>
<div className="mt-2">
<Dropdown
label="Select the default note type"
items={editorItems}
value={defaultEditorIdentifier}
onChange={(value) => selectEditorForNewNoteDefault(value as EditorOption['value'])}
/>
</div>
</div>
<HorizontalSeparator classes="my-4" />
<div>
<Subtitle>Title Format</Subtitle>
<div className="mt-2">
<Dropdown
label="Select the format for the note title"
items={NoteTitleFormatOptions}
value={newNoteTitleFormat}
onChange={setNewNoteTitleFormatChange}
/>
</div>
{newNoteTitleFormat === NewNoteTitleFormat.CustomFormat && (
<div className="mt-2">
<div className="mt-2">
<input
className={classNames(
'w-full min-w-55 rounded border border-solid border-passive-3 bg-default px-2 py-1.5 text-base md:w-auto md:translucent-ui:bg-transparent lg:text-sm',
'focus-within:ring-2 focus-within:ring-info',
)}
placeholder="e.g. YYYY-MM-DD"
value={customNoteTitleFormat}
onChange={handleCustomFormatInputChange}
spellCheck={false}
/>
</div>
<div className="mt-3 text-neutral">
<span className="font-bold">Preview: </span>
<ErrorBoundary>
<em>{getDayjsFormattedString(undefined, customNoteTitleFormat)}</em>
</ErrorBoundary>
</div>
<div className="mt-2 text-neutral">
<a
className="underline"
href={HelpPageUrl}
rel="noreferrer"
target="_blank"
onClick={(event) => {
if (application.isNativeMobileWeb()) {
event.preventDefault()
application.mobileDevice.openUrl(HelpPageUrl)
}
}}
>
Options
</a>
. Use <code>[]</code> to escape formatting.
</div>
</div>
)}
</div>
</div>
</PreferencesSegment>
</PreferencesGroup>
)
}
export default NewNoteDefaults