feat: add custom note title format pref (#1678)
This commit is contained in:
BIN
.yarn/cache/dayjs-npm-1.11.5-a825142dc5-e3bbaa7b48.zip
vendored
Normal file
BIN
.yarn/cache/dayjs-npm-1.11.5-a825142dc5-e3bbaa7b48.zip
vendored
Normal file
Binary file not shown.
@@ -33,11 +33,13 @@ export enum PrefKey {
|
|||||||
MobileSelectedTagUuid = 'mobileSelectedTagUuid',
|
MobileSelectedTagUuid = 'mobileSelectedTagUuid',
|
||||||
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
|
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
|
||||||
NewNoteTitleFormat = 'newNoteTitleFormat',
|
NewNoteTitleFormat = 'newNoteTitleFormat',
|
||||||
|
CustomNoteTitleFormat = 'customNoteTitleFormat',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum NewNoteTitleFormat {
|
export enum NewNoteTitleFormat {
|
||||||
CurrentDateAndTime = 'CurrentDateAndTime',
|
CurrentDateAndTime = 'CurrentDateAndTime',
|
||||||
CurrentNoteCount = 'CurrentNoteCount',
|
CurrentNoteCount = 'CurrentNoteCount',
|
||||||
|
CustomFormat = 'CustomFormat',
|
||||||
Empty = 'Empty',
|
Empty = 'Empty',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,4 +75,5 @@ export type PrefValue = {
|
|||||||
[PrefKey.MobileSelectedTagUuid]: string | undefined
|
[PrefKey.MobileSelectedTagUuid]: string | undefined
|
||||||
[PrefKey.MobileNotesHideEditorIcon]: boolean
|
[PrefKey.MobileNotesHideEditorIcon]: boolean
|
||||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
||||||
|
[PrefKey.CustomNoteTitleFormat]: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@
|
|||||||
"@standardnotes/toast": "workspace:*",
|
"@standardnotes/toast": "workspace:*",
|
||||||
"@standardnotes/ui-services": "workspace:^",
|
"@standardnotes/ui-services": "workspace:^",
|
||||||
"@zip.js/zip.js": "^2.6.26",
|
"@zip.js/zip.js": "^2.6.26",
|
||||||
|
"dayjs": "^1.11.5",
|
||||||
"mobx": "^6.6.2",
|
"mobx": "^6.6.2",
|
||||||
"mobx-react-lite": "^3.4.0",
|
"mobx-react-lite": "^3.4.0",
|
||||||
"qrcode.react": "^3.1.0",
|
"qrcode.react": "^3.1.0",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { DesktopManager } from './Device/DesktopManager'
|
|||||||
import { ArchiveManager, AutolockService, IOService, WebAlertService, ThemeManager } from '@standardnotes/ui-services'
|
import { ArchiveManager, AutolockService, IOService, WebAlertService, ThemeManager } from '@standardnotes/ui-services'
|
||||||
import { MobileWebReceiver } from './MobileWebReceiver'
|
import { MobileWebReceiver } from './MobileWebReceiver'
|
||||||
import { AndroidBackHandler } from '@/NativeMobileWeb/AndroidBackHandler'
|
import { AndroidBackHandler } from '@/NativeMobileWeb/AndroidBackHandler'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
type WebServices = {
|
type WebServices = {
|
||||||
viewControllerManager: ViewControllerManager
|
viewControllerManager: ViewControllerManager
|
||||||
@@ -210,7 +211,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
|||||||
}
|
}
|
||||||
|
|
||||||
isGlobalSpellcheckEnabled(): boolean {
|
isGlobalSpellcheckEnabled(): boolean {
|
||||||
return this.getPreference(PrefKey.EditorSpellcheck, true)
|
return this.getPreference(PrefKey.EditorSpellcheck, PrefDefaults[PrefKey.EditorSpellcheck])
|
||||||
}
|
}
|
||||||
|
|
||||||
public getItemTags(item: DecryptedItemInterface) {
|
public getItemTags(item: DecryptedItemInterface) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import MenuItem from '@/Components/Menu/MenuItem'
|
|||||||
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
|
||||||
import { MenuItemType } from '@/Components/Menu/MenuItemType'
|
import { MenuItemType } from '@/Components/Menu/MenuItemType'
|
||||||
import { DisplayOptionsMenuProps } from './DisplayOptionsMenuProps'
|
import { DisplayOptionsMenuProps } from './DisplayOptionsMenuProps'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||||
closeDisplayOptionsMenu,
|
closeDisplayOptionsMenu,
|
||||||
@@ -14,17 +15,35 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
|||||||
isOpen,
|
isOpen,
|
||||||
isFilesSmartView,
|
isFilesSmartView,
|
||||||
}) => {
|
}) => {
|
||||||
const [sortBy, setSortBy] = useState(() => application.getPreference(PrefKey.SortNotesBy, CollectionSort.CreatedAt))
|
const [sortBy, setSortBy] = useState(() =>
|
||||||
const [sortReverse, setSortReverse] = useState(() => application.getPreference(PrefKey.SortNotesReverse, false))
|
application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy]),
|
||||||
const [hidePreview, setHidePreview] = useState(() => application.getPreference(PrefKey.NotesHideNotePreview, false))
|
)
|
||||||
const [hideDate, setHideDate] = useState(() => application.getPreference(PrefKey.NotesHideDate, false))
|
const [sortReverse, setSortReverse] = useState(() =>
|
||||||
const [hideTags, setHideTags] = useState(() => application.getPreference(PrefKey.NotesHideTags, true))
|
application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]),
|
||||||
const [hidePinned, setHidePinned] = useState(() => application.getPreference(PrefKey.NotesHidePinned, false))
|
)
|
||||||
const [showArchived, setShowArchived] = useState(() => application.getPreference(PrefKey.NotesShowArchived, false))
|
const [hidePreview, setHidePreview] = useState(() =>
|
||||||
const [showTrashed, setShowTrashed] = useState(() => application.getPreference(PrefKey.NotesShowTrashed, false))
|
application.getPreference(PrefKey.NotesHideNotePreview, PrefDefaults[PrefKey.NotesHideNotePreview]),
|
||||||
const [hideProtected, setHideProtected] = useState(() => application.getPreference(PrefKey.NotesHideProtected, false))
|
)
|
||||||
|
const [hideDate, setHideDate] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesHideDate, PrefDefaults[PrefKey.NotesHideDate]),
|
||||||
|
)
|
||||||
|
const [hideTags, setHideTags] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesHideTags, PrefDefaults[PrefKey.NotesHideTags]),
|
||||||
|
)
|
||||||
|
const [hidePinned, setHidePinned] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesHidePinned, PrefDefaults[PrefKey.NotesHidePinned]),
|
||||||
|
)
|
||||||
|
const [showArchived, setShowArchived] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived]),
|
||||||
|
)
|
||||||
|
const [showTrashed, setShowTrashed] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesShowTrashed, PrefDefaults[PrefKey.NotesShowTrashed]),
|
||||||
|
)
|
||||||
|
const [hideProtected, setHideProtected] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.NotesHideProtected, PrefDefaults[PrefKey.NotesHideProtected]),
|
||||||
|
)
|
||||||
const [hideEditorIcon, setHideEditorIcon] = useState(() =>
|
const [hideEditorIcon, setHideEditorIcon] = useState(() =>
|
||||||
application.getPreference(PrefKey.NotesHideEditorIcon, false),
|
application.getPreference(PrefKey.NotesHideEditorIcon, PrefDefaults[PrefKey.NotesHideEditorIcon]),
|
||||||
)
|
)
|
||||||
|
|
||||||
const toggleSortReverse = useCallback(() => {
|
const toggleSortReverse = useCallback(() => {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
|||||||
id="navigation"
|
id="navigation"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'sn-component section app-column h-screen max-h-screen overflow-hidden pt-safe-top md:h-full md:max-h-full md:min-h-0 md:pb-0',
|
'sn-component section app-column h-screen max-h-screen overflow-hidden pt-safe-top md:h-full md:max-h-full md:min-h-0 md:pb-0',
|
||||||
'w-[220px] xl:w-87.5 xsm-only:!w-full sm-only:!w-full',
|
'w-[220px] xl:w-[220px] xsm-only:!w-full sm-only:!w-full',
|
||||||
selectedPane === AppPaneId.Navigation
|
selectedPane === AppPaneId.Navigation
|
||||||
? 'pointer-coarse:md-only:!w-48 pointer-coarse:lg-only:!w-48'
|
? 'pointer-coarse:md-only:!w-48 pointer-coarse:lg-only:!w-48'
|
||||||
: 'pointer-coarse:md-only:!w-0 pointer-coarse:lg-only:!w-0',
|
: 'pointer-coarse:md-only:!w-0 pointer-coarse:lg-only:!w-0',
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import AutoresizingNoteViewTextarea from './AutoresizingTextarea'
|
|||||||
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
|
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
|
||||||
import NoteTagsPanel from '../NoteTags/NoteTagsPanel'
|
import NoteTagsPanel from '../NoteTags/NoteTagsPanel'
|
||||||
import NoteTagsContainer from '../NoteTags/NoteTagsContainer'
|
import NoteTagsContainer from '../NoteTags/NoteTagsContainer'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
const MinimumStatusDuration = 400
|
const MinimumStatusDuration = 400
|
||||||
const TextareaDebounce = 100
|
const TextareaDebounce = 100
|
||||||
@@ -686,9 +687,15 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async reloadPreferences() {
|
async reloadPreferences() {
|
||||||
const monospaceFont = this.application.getPreference(PrefKey.EditorMonospaceEnabled, true)
|
const monospaceFont = this.application.getPreference(
|
||||||
|
PrefKey.EditorMonospaceEnabled,
|
||||||
|
PrefDefaults[PrefKey.EditorMonospaceEnabled],
|
||||||
|
)
|
||||||
|
|
||||||
const marginResizersEnabled = this.application.getPreference(PrefKey.EditorResizersEnabled, true)
|
const marginResizersEnabled = this.application.getPreference(
|
||||||
|
PrefKey.EditorResizersEnabled,
|
||||||
|
PrefDefaults[PrefKey.EditorResizersEnabled],
|
||||||
|
)
|
||||||
|
|
||||||
await this.reloadSpellcheck()
|
await this.reloadSpellcheck()
|
||||||
|
|
||||||
@@ -700,14 +707,14 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
|||||||
reloadFont(monospaceFont)
|
reloadFont(monospaceFont)
|
||||||
|
|
||||||
if (marginResizersEnabled) {
|
if (marginResizersEnabled) {
|
||||||
const width = this.application.getPreference(PrefKey.EditorWidth, null)
|
const width = this.application.getPreference(PrefKey.EditorWidth, PrefDefaults[PrefKey.EditorWidth])
|
||||||
if (width != null) {
|
if (width != null) {
|
||||||
this.setState({
|
this.setState({
|
||||||
leftResizerWidth: width,
|
leftResizerWidth: width,
|
||||||
rightResizerWidth: width,
|
rightResizerWidth: width,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const left = this.application.getPreference(PrefKey.EditorLeft, null)
|
const left = this.application.getPreference(PrefKey.EditorLeft, PrefDefaults[PrefKey.EditorLeft])
|
||||||
if (left != null) {
|
if (left != null) {
|
||||||
this.setState({
|
this.setState({
|
||||||
leftResizerOffset: left,
|
leftResizerOffset: left,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import PreferencesPane from '../PreferencesComponents/PreferencesPane'
|
|||||||
import PreferencesGroup from '../PreferencesComponents/PreferencesGroup'
|
import PreferencesGroup from '../PreferencesComponents/PreferencesGroup'
|
||||||
import PreferencesSegment from '../PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '../PreferencesComponents/PreferencesSegment'
|
||||||
import { PremiumFeatureIconName } from '@/Components/Icon/PremiumFeatureIcon'
|
import { PremiumFeatureIconName } from '@/Components/Icon/PremiumFeatureIcon'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -24,18 +25,17 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
|||||||
application.features.getFeatureStatus(FeatureIdentifier.MidnightTheme) === FeatureStatus.Entitled
|
application.features.getFeatureStatus(FeatureIdentifier.MidnightTheme) === FeatureStatus.Entitled
|
||||||
|
|
||||||
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
|
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
|
||||||
const [autoLightTheme, setAutoLightTheme] = useState<string>(
|
const [autoLightTheme, setAutoLightTheme] = useState<string>(() =>
|
||||||
() => application.getPreference(PrefKey.AutoLightThemeIdentifier, 'Default') as string,
|
application.getPreference(PrefKey.AutoLightThemeIdentifier, PrefDefaults[PrefKey.AutoLightThemeIdentifier]),
|
||||||
)
|
)
|
||||||
const [autoDarkTheme, setAutoDarkTheme] = useState<string>(
|
const [autoDarkTheme, setAutoDarkTheme] = useState<string>(() =>
|
||||||
() =>
|
application.getPreference(
|
||||||
application.getPreference(
|
PrefKey.AutoDarkThemeIdentifier,
|
||||||
PrefKey.AutoDarkThemeIdentifier,
|
isEntitledToMidnightTheme ? FeatureIdentifier.MidnightTheme : PrefDefaults[PrefKey.AutoDarkThemeIdentifier],
|
||||||
isEntitledToMidnightTheme ? FeatureIdentifier.MidnightTheme : 'Default',
|
),
|
||||||
) as string,
|
|
||||||
)
|
)
|
||||||
const [useDeviceSettings, setUseDeviceSettings] = useState(
|
const [useDeviceSettings, setUseDeviceSettings] = useState(() =>
|
||||||
() => application.getPreference(PrefKey.UseSystemColorScheme, false) as boolean,
|
application.getPreference(PrefKey.UseSystemColorScheme, PrefDefaults[PrefKey.UseSystemColorScheme]),
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -11,13 +11,15 @@ import {
|
|||||||
} from '@standardnotes/snjs'
|
} from '@standardnotes/snjs'
|
||||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
import { WebApplication } from '@/Application/Application'
|
import { WebApplication } from '@/Application/Application'
|
||||||
import { FunctionComponent, useEffect, useState } from 'react'
|
import { FunctionComponent, useEffect, useMemo, useState } from 'react'
|
||||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||||
import Switch from '@/Components/Switch/Switch'
|
import Switch from '@/Components/Switch/Switch'
|
||||||
import { PLAIN_EDITOR_NAME } from '@/Constants/Constants'
|
import { PLAIN_EDITOR_NAME } from '@/Constants/Constants'
|
||||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||||
import Button from '@/Components/Button/Button'
|
import Button from '@/Components/Button/Button'
|
||||||
|
import CustomNoteTitleFormat from './Defaults/CustomNoteTitleFormat'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -60,10 +62,12 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
() => getDefaultEditor(application)?.package_info?.identifier || 'plain-editor',
|
() => getDefaultEditor(application)?.package_info?.identifier || 'plain-editor',
|
||||||
)
|
)
|
||||||
|
|
||||||
const [spellcheck, setSpellcheck] = useState(() => application.getPreference(PrefKey.EditorSpellcheck, true))
|
const [spellcheck, setSpellcheck] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.EditorSpellcheck, PrefDefaults[PrefKey.EditorSpellcheck]),
|
||||||
|
)
|
||||||
|
|
||||||
const [newNoteTitleFormat, setNewNoteTitleFormat] = useState(() =>
|
const [newNoteTitleFormat, setNewNoteTitleFormat] = useState(() =>
|
||||||
application.getPreference(PrefKey.NewNoteTitleFormat, NewNoteTitleFormat.CurrentDateAndTime),
|
application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]),
|
||||||
)
|
)
|
||||||
const handleNewNoteTitleFormatChange = (value: string) => {
|
const handleNewNoteTitleFormatChange = (value: string) => {
|
||||||
setNewNoteTitleFormat(value as NewNoteTitleFormat)
|
setNewNoteTitleFormat(value as NewNoteTitleFormat)
|
||||||
@@ -71,7 +75,7 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [addNoteToParentFolders, setAddNoteToParentFolders] = useState(() =>
|
const [addNoteToParentFolders, setAddNoteToParentFolders] = useState(() =>
|
||||||
application.getPreference(PrefKey.NoteAddToParentFolders, true),
|
application.getPreference(PrefKey.NoteAddToParentFolders, PrefDefaults[PrefKey.NoteAddToParentFolders]),
|
||||||
)
|
)
|
||||||
|
|
||||||
const toggleSpellcheck = () => {
|
const toggleSpellcheck = () => {
|
||||||
@@ -128,6 +132,28 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const noteTitleFormatOptions = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
label: 'Current date and time',
|
||||||
|
value: NewNoteTitleFormat.CurrentDateAndTime,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Current note count',
|
||||||
|
value: NewNoteTitleFormat.CurrentNoteCount,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Custom format',
|
||||||
|
value: NewNoteTitleFormat.CustomFormat,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Empty',
|
||||||
|
value: NewNoteTitleFormat.Empty,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PreferencesGroup>
|
<PreferencesGroup>
|
||||||
<PreferencesSegment>
|
<PreferencesSegment>
|
||||||
@@ -166,25 +192,13 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
id="def-new-note-title-format"
|
id="def-new-note-title-format"
|
||||||
label="Select the default note type"
|
label="Select the default note type"
|
||||||
items={[
|
items={noteTitleFormatOptions}
|
||||||
{
|
|
||||||
label: 'Current date and time',
|
|
||||||
value: NewNoteTitleFormat.CurrentDateAndTime,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Current note count',
|
|
||||||
value: NewNoteTitleFormat.CurrentNoteCount,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Empty',
|
|
||||||
value: NewNoteTitleFormat.Empty,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
value={newNoteTitleFormat}
|
value={newNoteTitleFormat}
|
||||||
onChange={handleNewNoteTitleFormatChange}
|
onChange={handleNewNoteTitleFormatChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{newNoteTitleFormat === NewNoteTitleFormat.CustomFormat && <CustomNoteTitleFormat application={application} />}
|
||||||
<HorizontalSeparator classes="my-4" />
|
<HorizontalSeparator classes="my-4" />
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { WebApplication } from '@/Application/Application'
|
||||||
|
import { Text, Subtitle } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
|
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
import { PrefKey } from '@standardnotes/snjs'
|
||||||
|
import { ChangeEventHandler, useRef, useState } from 'react'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
application: WebApplication
|
||||||
|
}
|
||||||
|
|
||||||
|
const PrefChangeDebounceTimeInMs = 25
|
||||||
|
|
||||||
|
const CustomNoteTitleFormat = ({ application }: Props) => {
|
||||||
|
const [customNoteTitleFormat, setCustomNoteTitleFormat] = useState(() =>
|
||||||
|
application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat]),
|
||||||
|
)
|
||||||
|
|
||||||
|
const setCustomNoteTitleFormatPreference = () => {
|
||||||
|
application.setPreference(PrefKey.CustomNoteTitleFormat, customNoteTitleFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
const debounceTimeoutRef = useRef<number>()
|
||||||
|
|
||||||
|
const handleInputChange: ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||||
|
setCustomNoteTitleFormat(event.currentTarget.value)
|
||||||
|
|
||||||
|
if (debounceTimeoutRef.current) {
|
||||||
|
clearTimeout(debounceTimeoutRef.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
debounceTimeoutRef.current = window.setTimeout(async () => {
|
||||||
|
setCustomNoteTitleFormatPreference()
|
||||||
|
}, PrefChangeDebounceTimeInMs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<HorizontalSeparator classes="my-4" />
|
||||||
|
<div>
|
||||||
|
<Subtitle>Custom Note Title Format</Subtitle>
|
||||||
|
<Text>
|
||||||
|
All available date-time formatting options can be found{' '}
|
||||||
|
<a className="underline" href="https://day.js.org/docs/en/display/format#list-of-all-available-formats">
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
. Use square brackets (<code>[]</code>) to escape date-time formatting.
|
||||||
|
</Text>
|
||||||
|
<div className="mt-2">
|
||||||
|
<input
|
||||||
|
className="min-w-55 rounded border border-solid border-passive-3 bg-default px-2 py-1.5 text-sm focus-within:ring-2 focus-within:ring-info"
|
||||||
|
placeholder="e.g. YYYY-MM-DD"
|
||||||
|
value={customNoteTitleFormat}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onBlur={setCustomNoteTitleFormatPreference}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2">
|
||||||
|
<span className="font-bold">Preview:</span> {dayjs().format(customNoteTitleFormat)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomNoteTitleFormat
|
||||||
@@ -7,6 +7,7 @@ import { observer } from 'mobx-react-lite'
|
|||||||
import { FunctionComponent, useState } from 'react'
|
import { FunctionComponent, useState } from 'react'
|
||||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -14,10 +15,10 @@ type Props = {
|
|||||||
|
|
||||||
const Tools: FunctionComponent<Props> = ({ application }: Props) => {
|
const Tools: FunctionComponent<Props> = ({ application }: Props) => {
|
||||||
const [monospaceFont, setMonospaceFont] = useState(() =>
|
const [monospaceFont, setMonospaceFont] = useState(() =>
|
||||||
application.getPreference(PrefKey.EditorMonospaceEnabled, true),
|
application.getPreference(PrefKey.EditorMonospaceEnabled, PrefDefaults[PrefKey.EditorMonospaceEnabled]),
|
||||||
)
|
)
|
||||||
const [marginResizers, setMarginResizers] = useState(() =>
|
const [marginResizers, setMarginResizers] = useState(() =>
|
||||||
application.getPreference(PrefKey.EditorResizersEnabled, true),
|
application.getPreference(PrefKey.EditorResizersEnabled, PrefDefaults[PrefKey.EditorResizersEnabled]),
|
||||||
)
|
)
|
||||||
|
|
||||||
const toggleMonospaceFont = () => {
|
const toggleMonospaceFont = () => {
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import MenuItem from '../Menu/MenuItem'
|
|||||||
import { MenuItemType } from '../Menu/MenuItemType'
|
import { MenuItemType } from '../Menu/MenuItemType'
|
||||||
import { PANEL_NAME_NAVIGATION, PANEL_NAME_NOTES } from '@/Constants/Constants'
|
import { PANEL_NAME_NAVIGATION, PANEL_NAME_NOTES } from '@/Constants/Constants'
|
||||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
const WidthForCollapsedPanel = 5
|
const WidthForCollapsedPanel = 5
|
||||||
const MinimumNavPanelWidth = 220
|
const MinimumNavPanelWidth = PrefDefaults[PrefKey.TagsPanelWidth]
|
||||||
const MinimumNotesPanelWidth = 350
|
const MinimumNotesPanelWidth = PrefDefaults[PrefKey.NotesPanelWidth]
|
||||||
|
|
||||||
const PanelSettingsSection = ({ application }: Props) => {
|
const PanelSettingsSection = ({ application }: Props) => {
|
||||||
const [currentNavPanelWidth, setCurrentNavPanelWidth] = useState(
|
const [currentNavPanelWidth, setCurrentNavPanelWidth] = useState(
|
||||||
|
|||||||
27
packages/web/src/javascripts/Constants/PrefDefaults.ts
Normal file
27
packages/web/src/javascripts/Constants/PrefDefaults.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { PrefKey, CollectionSort, NewNoteTitleFormat } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export const PrefDefaults = {
|
||||||
|
[PrefKey.TagsPanelWidth]: 220,
|
||||||
|
[PrefKey.NotesPanelWidth]: 350,
|
||||||
|
[PrefKey.EditorWidth]: null,
|
||||||
|
[PrefKey.EditorLeft]: null,
|
||||||
|
[PrefKey.EditorMonospaceEnabled]: true,
|
||||||
|
[PrefKey.EditorSpellcheck]: true,
|
||||||
|
[PrefKey.EditorResizersEnabled]: true,
|
||||||
|
[PrefKey.SortNotesBy]: CollectionSort.CreatedAt,
|
||||||
|
[PrefKey.SortNotesReverse]: false,
|
||||||
|
[PrefKey.NotesShowArchived]: false,
|
||||||
|
[PrefKey.NotesShowTrashed]: false,
|
||||||
|
[PrefKey.NotesHidePinned]: false,
|
||||||
|
[PrefKey.NotesHideProtected]: false,
|
||||||
|
[PrefKey.NotesHideNotePreview]: false,
|
||||||
|
[PrefKey.NotesHideDate]: false,
|
||||||
|
[PrefKey.NotesHideTags]: true,
|
||||||
|
[PrefKey.NotesHideEditorIcon]: false,
|
||||||
|
[PrefKey.UseSystemColorScheme]: false,
|
||||||
|
[PrefKey.AutoLightThemeIdentifier]: 'Default',
|
||||||
|
[PrefKey.AutoDarkThemeIdentifier]: 'Default',
|
||||||
|
[PrefKey.NoteAddToParentFolders]: true,
|
||||||
|
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
|
||||||
|
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
|
||||||
|
} as const
|
||||||
@@ -31,6 +31,8 @@ import { SelectedItemsController } from '../SelectedItemsController'
|
|||||||
import { NotesController } from '../NotesController'
|
import { NotesController } from '../NotesController'
|
||||||
import { NoteTagsController } from '../NoteTagsController'
|
import { NoteTagsController } from '../NoteTagsController'
|
||||||
import { formatDateAndTimeForNote } from '@/Utils/DateUtils'
|
import { formatDateAndTimeForNote } from '@/Utils/DateUtils'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
const MinNoteCellHeight = 51.0
|
const MinNoteCellHeight = 51.0
|
||||||
const DefaultListNumNotes = 20
|
const DefaultListNumNotes = 20
|
||||||
@@ -351,7 +353,7 @@ export class ItemListController extends AbstractViewController implements Intern
|
|||||||
const shouldShowArchivedNotes =
|
const shouldShowArchivedNotes =
|
||||||
this.navigationController.isInSystemView(SystemViewId.ArchivedNotes) ||
|
this.navigationController.isInSystemView(SystemViewId.ArchivedNotes) ||
|
||||||
this.searchOptionsController.includeArchived ||
|
this.searchOptionsController.includeArchived ||
|
||||||
this.application.getPreference(PrefKey.NotesShowArchived, false)
|
this.application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived])
|
||||||
|
|
||||||
return (activeItem?.trashed && !shouldShowTrashedNotes) || (activeItem?.archived && !shouldShowArchivedNotes)
|
return (activeItem?.trashed && !shouldShowTrashedNotes) || (activeItem?.archived && !shouldShowArchivedNotes)
|
||||||
}
|
}
|
||||||
@@ -421,23 +423,49 @@ export class ItemListController extends AbstractViewController implements Intern
|
|||||||
|
|
||||||
const currentSortBy = this.displayOptions.sortBy
|
const currentSortBy = this.displayOptions.sortBy
|
||||||
|
|
||||||
let sortBy = this.application.getPreference(PrefKey.SortNotesBy, CollectionSort.CreatedAt)
|
let sortBy = this.application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy])
|
||||||
if (sortBy === CollectionSort.UpdatedAt || (sortBy as string) === 'client_updated_at') {
|
if (sortBy === CollectionSort.UpdatedAt || (sortBy as string) === 'client_updated_at') {
|
||||||
sortBy = CollectionSort.UpdatedAt
|
sortBy = CollectionSort.UpdatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
newDisplayOptions.sortBy = sortBy
|
newDisplayOptions.sortBy = sortBy
|
||||||
newDisplayOptions.sortDirection =
|
newDisplayOptions.sortDirection =
|
||||||
this.application.getPreference(PrefKey.SortNotesReverse, false) === false ? 'dsc' : 'asc'
|
this.application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]) === false
|
||||||
newDisplayOptions.includeArchived = this.application.getPreference(PrefKey.NotesShowArchived, false)
|
? 'dsc'
|
||||||
newDisplayOptions.includeTrashed = this.application.getPreference(PrefKey.NotesShowTrashed, false) as boolean
|
: 'asc'
|
||||||
newDisplayOptions.includePinned = !this.application.getPreference(PrefKey.NotesHidePinned, false)
|
newDisplayOptions.includeArchived = this.application.getPreference(
|
||||||
newDisplayOptions.includeProtected = !this.application.getPreference(PrefKey.NotesHideProtected, false)
|
PrefKey.NotesShowArchived,
|
||||||
|
PrefDefaults[PrefKey.NotesShowArchived],
|
||||||
|
)
|
||||||
|
newDisplayOptions.includeTrashed = this.application.getPreference(
|
||||||
|
PrefKey.NotesShowTrashed,
|
||||||
|
PrefDefaults[PrefKey.NotesShowTrashed],
|
||||||
|
) as boolean
|
||||||
|
newDisplayOptions.includePinned = !this.application.getPreference(
|
||||||
|
PrefKey.NotesHidePinned,
|
||||||
|
PrefDefaults[PrefKey.NotesHidePinned],
|
||||||
|
)
|
||||||
|
newDisplayOptions.includeProtected = !this.application.getPreference(
|
||||||
|
PrefKey.NotesHideProtected,
|
||||||
|
PrefDefaults[PrefKey.NotesHideProtected],
|
||||||
|
)
|
||||||
|
|
||||||
newWebDisplayOptions.hideNotePreview = this.application.getPreference(PrefKey.NotesHideNotePreview, false)
|
newWebDisplayOptions.hideNotePreview = this.application.getPreference(
|
||||||
newWebDisplayOptions.hideDate = this.application.getPreference(PrefKey.NotesHideDate, false)
|
PrefKey.NotesHideNotePreview,
|
||||||
newWebDisplayOptions.hideTags = this.application.getPreference(PrefKey.NotesHideTags, true)
|
PrefDefaults[PrefKey.NotesHideNotePreview],
|
||||||
newWebDisplayOptions.hideEditorIcon = this.application.getPreference(PrefKey.NotesHideEditorIcon, false)
|
)
|
||||||
|
newWebDisplayOptions.hideDate = this.application.getPreference(
|
||||||
|
PrefKey.NotesHideDate,
|
||||||
|
PrefDefaults[PrefKey.NotesHideDate],
|
||||||
|
)
|
||||||
|
newWebDisplayOptions.hideTags = this.application.getPreference(
|
||||||
|
PrefKey.NotesHideTags,
|
||||||
|
PrefDefaults[PrefKey.NotesHideTags],
|
||||||
|
)
|
||||||
|
newWebDisplayOptions.hideEditorIcon = this.application.getPreference(
|
||||||
|
PrefKey.NotesHideEditorIcon,
|
||||||
|
PrefDefaults[PrefKey.NotesHideEditorIcon],
|
||||||
|
)
|
||||||
|
|
||||||
const displayOptionsChanged =
|
const displayOptionsChanged =
|
||||||
newDisplayOptions.sortBy !== this.displayOptions.sortBy ||
|
newDisplayOptions.sortBy !== this.displayOptions.sortBy ||
|
||||||
@@ -494,13 +522,19 @@ export class ItemListController extends AbstractViewController implements Intern
|
|||||||
|
|
||||||
const titleFormat = this.application.getPreference(
|
const titleFormat = this.application.getPreference(
|
||||||
PrefKey.NewNoteTitleFormat,
|
PrefKey.NewNoteTitleFormat,
|
||||||
NewNoteTitleFormat.CurrentDateAndTime,
|
PrefDefaults[PrefKey.NewNoteTitleFormat],
|
||||||
)
|
)
|
||||||
|
|
||||||
let title = formatDateAndTimeForNote(new Date())
|
let title = formatDateAndTimeForNote(new Date())
|
||||||
|
|
||||||
if (titleFormat === NewNoteTitleFormat.CurrentNoteCount) {
|
if (titleFormat === NewNoteTitleFormat.CurrentNoteCount) {
|
||||||
title = `Note ${this.notes.length + 1}`
|
title = `Note ${this.notes.length + 1}`
|
||||||
|
} else if (titleFormat === NewNoteTitleFormat.CustomFormat) {
|
||||||
|
const customFormat = this.application.getPreference(
|
||||||
|
PrefKey.CustomNoteTitleFormat,
|
||||||
|
PrefDefaults[PrefKey.CustomNoteTitleFormat],
|
||||||
|
)
|
||||||
|
title = dayjs().format(customFormat)
|
||||||
} else if (titleFormat === NewNoteTitleFormat.Empty) {
|
} else if (titleFormat === NewNoteTitleFormat.Empty) {
|
||||||
title = ''
|
title = ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ElementIds } from '@/Constants/ElementIDs'
|
import { ElementIds } from '@/Constants/ElementIDs'
|
||||||
|
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||||
import { destroyAllObjectProperties } from '@/Utils'
|
import { destroyAllObjectProperties } from '@/Utils'
|
||||||
import {
|
import {
|
||||||
ApplicationEvent,
|
ApplicationEvent,
|
||||||
@@ -60,7 +61,10 @@ export class NoteTagsController extends AbstractViewController {
|
|||||||
setTagsContainerMaxWidth: action,
|
setTagsContainerMaxWidth: action,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.addNoteToParentFolders = application.getPreference(PrefKey.NoteAddToParentFolders, true)
|
this.addNoteToParentFolders = application.getPreference(
|
||||||
|
PrefKey.NoteAddToParentFolders,
|
||||||
|
PrefDefaults[PrefKey.NoteAddToParentFolders],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public setServicesPostConstruction(itemListController: ItemListController) {
|
public setServicesPostConstruction(itemListController: ItemListController) {
|
||||||
@@ -71,7 +75,10 @@ export class NoteTagsController extends AbstractViewController {
|
|||||||
this.reloadTagsForCurrentNote()
|
this.reloadTagsForCurrentNote()
|
||||||
}),
|
}),
|
||||||
this.application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
|
this.application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
|
||||||
this.addNoteToParentFolders = this.application.getPreference(PrefKey.NoteAddToParentFolders, true)
|
this.addNoteToParentFolders = this.application.getPreference(
|
||||||
|
PrefKey.NoteAddToParentFolders,
|
||||||
|
PrefDefaults[PrefKey.NoteAddToParentFolders],
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7713,6 +7713,7 @@ __metadata:
|
|||||||
circular-dependency-plugin: ^5.2.2
|
circular-dependency-plugin: ^5.2.2
|
||||||
copy-webpack-plugin: ^11.0.0
|
copy-webpack-plugin: ^11.0.0
|
||||||
css-loader: "*"
|
css-loader: "*"
|
||||||
|
dayjs: ^1.11.5
|
||||||
dotenv: ^16.0.2
|
dotenv: ^16.0.2
|
||||||
eslint: ^8.23.1
|
eslint: ^8.23.1
|
||||||
eslint-config-prettier: ^8.5.0
|
eslint-config-prettier: ^8.5.0
|
||||||
@@ -16129,6 +16130,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"dayjs@npm:^1.11.5":
|
||||||
|
version: 1.11.5
|
||||||
|
resolution: "dayjs@npm:1.11.5"
|
||||||
|
checksum: e3bbaa7b4883b31be4bf75a181f1447fbb19800c29b332852125aab96baeff3ac232dcba8b88c4ea17d3b636c99dac5fb9d1af4bb6ae26615698bbc4a852dffb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"dayjs@npm:^1.8.15":
|
"dayjs@npm:^1.8.15":
|
||||||
version: 1.11.3
|
version: 1.11.3
|
||||||
resolution: "dayjs@npm:1.11.3"
|
resolution: "dayjs@npm:1.11.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user