diff --git a/docs/ABSTRACTIONS.md b/docs/ABSTRACTIONS.md
index c05cff34..2df689a4 100644
--- a/docs/ABSTRACTIONS.md
+++ b/docs/ABSTRACTIONS.md
@@ -852,7 +852,7 @@ interface Settings {
}
```
-Managed by `useSettings` hook and `SettingsPanel` component. `theme_mode` is installation-local because it controls device comfort rather than vault structure; the Settings panel and command-palette Light/Dark/System actions both update that same value. `system` remains a stored preference, while the runtime resolves it to `light` or `dark` for `data-theme` and app consumers. `ui_language` is also installation-local: `null` follows the supported system language with English fallback, while explicit values pin the UI language for this installation. Stored legacy aliases such as `zh-Hans` are normalized to canonical locale codes before the setting reaches React state. `date_display_format` is installation-local and controls rendered dates in note rows, property chips/cells, note info, table-of-contents metadata, and search result subtitles; date picker text input remains ISO for predictable manual entry and storage. `note_width_mode` is the installation-local default for rich-editor note width; individual notes can override it with `_width` when they already have frontmatter. `sidebar_type_pluralization_enabled` is installation-local and defaults to `true`; when false, type rows use exact type names unless the type document defines an explicit `sidebar_label` override. `default_ai_agent` remains the legacy installation-local CLI fallback. `default_ai_target` is the active AI target used by the AI panel and status bar; it can point at a coding agent or a configured direct model. `ai_model_providers` stores non-secret provider metadata for local/API model targets, while hosted API keys live in Tolaria's local app-data secrets file or user-managed environment variables instead of being persisted in app settings. Provider defaults and local/API grouping come from the shared `src/shared/aiModelProviderCatalog.json` catalog used by both renderer settings and the Tauri direct-model runtime. `hide_gitignored_files` is also installation-local and defaults to `true`; changing it reloads entries, search, saved views, and folders without restarting. The `all_notes_show_pdfs`, `all_notes_show_images`, and `all_notes_show_unsupported` flags are installation-local All Notes category toggles that default off and update the list/counts without changing vault files. The AutoGit fields are also installation-local: `useAutoGit` consumes them to schedule automatic checkpoints, while `useCommitFlow` and the status bar quick action reuse the same checkpoint runner and deterministic automatic commit message generation.
+Managed by `useSettings` hook and `SettingsPanel` component. `theme_mode` is installation-local because it controls device comfort rather than vault structure; the Settings panel and command-palette Light/Dark/System actions both update that same value. `system` remains a stored preference, while the runtime resolves it to `light` or `dark` for `data-theme` and app consumers. `ui_language` is also installation-local: `null` follows the supported system language with English fallback, while explicit values pin the UI language for this installation. Stored legacy aliases such as `zh-Hans` are normalized to canonical locale codes before the setting reaches React state. `date_display_format` is installation-local and controls rendered dates in note rows, property chips/cells, note info, table-of-contents metadata, and search result subtitles; `AppPreferencesProvider` owns the UI-level value so rendering surfaces can consume it without prop forwarding, while date picker text input remains ISO for predictable manual entry and storage. `note_width_mode` is the installation-local default for rich-editor note width; individual notes can override it with `_width` when they already have frontmatter. `sidebar_type_pluralization_enabled` is installation-local and defaults to `true`; when false, type rows use exact type names unless the type document defines an explicit `sidebar_label` override. `default_ai_agent` remains the legacy installation-local CLI fallback. `default_ai_target` is the active AI target used by the AI panel and status bar; it can point at a coding agent or a configured direct model. `ai_model_providers` stores non-secret provider metadata for local/API model targets, while hosted API keys live in Tolaria's local app-data secrets file or user-managed environment variables instead of being persisted in app settings. Provider defaults and local/API grouping come from the shared `src/shared/aiModelProviderCatalog.json` catalog used by both renderer settings and the Tauri direct-model runtime. `hide_gitignored_files` is also installation-local and defaults to `true`; changing it reloads entries, search, saved views, and folders without restarting. The `all_notes_show_pdfs`, `all_notes_show_images`, and `all_notes_show_unsupported` flags are installation-local All Notes category toggles that default off and update the list/counts without changing vault files. The AutoGit fields are also installation-local: `useAutoGit` consumes them to schedule automatic checkpoints, while `useCommitFlow` and the status bar quick action reuse the same checkpoint runner and deterministic automatic commit message generation.
## Telemetry
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 51165de8..5b506263 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -478,7 +478,7 @@ Tolaria's app chrome uses an app-owned localization runtime in `src/lib/i18n.ts`
`App.tsx` derives the effective locale from settings and browser/system language hints, then passes it down to localized surfaces. Settings exposes a keyboard-accessible shadcn `Select`, and the command palette includes actions to open language settings or switch directly to a supported language.
-`App.tsx` also resolves the installation-local date display format from `settings.date_display_format`. Note rows, note-list property chips, inspector property cells, note info, table-of-contents metadata, and search result subtitles render dates through the same `src/utils/dateDisplay.ts` formatter so the visible style stays consistent. Date picker text entry remains ISO (`YYYY-MM-DD`) to preserve predictable manual input and frontmatter storage.
+`App.tsx` also resolves the installation-local date display format from `settings.date_display_format` and publishes it through `AppPreferencesProvider` in `src/hooks/useAppPreferences.ts`. Note rows, note-list property chips, inspector property cells, note info, table-of-contents metadata, and search result subtitles read that shared preference and render dates through `src/utils/dateDisplay.ts` so the visible style stays consistent. Date picker text entry remains ISO (`YYYY-MM-DD`) to preserve predictable manual input and frontmatter storage.
## Vault Management
diff --git a/src/App.tsx b/src/App.tsx
index a23e94a1..a176493a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -119,7 +119,7 @@ import {
import { activeGitRepositories } from './utils/gitRepositories'
import { useVisibleWorkspaceEntries, useWorkspaceGraphState } from './hooks/useWorkspaceGraphState'
import { useGitSetupState } from './hooks/useGitSetupState'
-import { useAppPreferences } from './hooks/useAppPreferences'
+import { AppPreferencesProvider, useAppPreferences } from './hooks/useAppPreferences'
import { useInboxOrganizeAdvance } from './hooks/useInboxOrganizeAdvance'
import { syncVaultAssetScope, useNoteWindowLifecycle } from './hooks/useNoteWindowLifecycle'
import { useVaultRenameDetection } from './hooks/useVaultRenameDetection'
@@ -1589,7 +1589,8 @@ function App() {
const noteListModifiedFilesError = isChangesSelection ? gitSurfaces.changesModifiedFilesError : null
return (
-
+
+
{sidebarVisible && (
<>
@@ -1605,7 +1606,7 @@ function App() {
{effectiveSelection.kind === 'filter' && effectiveSelection.filter === 'pulse' ? (
handleSetViewMode('all')} repositories={gitRepositories} selectedRepositoryPath={gitSurfaces.historyRepositoryPath} onRepositoryChange={gitSurfaces.setHistoryRepositoryPath} locale={appLocale} />
) : (
-
+
)}
@@ -1682,7 +1683,6 @@ function App() {
flushPendingEditorContentRef={flushPendingEditorContentRef}
flushPendingRawContentRef={flushPendingRawContentRef}
locale={appLocale}
- dateDisplayFormat={dateDisplayFormat}
/>
@@ -1702,7 +1702,7 @@ function App() {
locale={appLocale}
onClose={dialogs.closeCommandPalette}
/>
-
+
)}
-
+
+
)
}
diff --git a/src/components/AddPropertyForm.tsx b/src/components/AddPropertyForm.tsx
index 0eb8a6f2..677e4d7d 100644
--- a/src/components/AddPropertyForm.tsx
+++ b/src/components/AddPropertyForm.tsx
@@ -10,10 +10,10 @@ import {
formatDateValue,
toISODate,
} from '../utils/propertyTypes'
-import { DEFAULT_DATE_DISPLAY_FORMAT, type DateDisplayFormat } from '../utils/dateDisplay'
import { StatusPill, StatusDropdown } from './StatusDropdown'
import { DISPLAY_MODE_OPTIONS, DISPLAY_MODE_ICONS } from '../utils/propertyTypes'
import { translate, type AppLocale } from '../lib/i18n'
+import { useDateDisplayFormat } from '../hooks/useAppPreferences'
function parseDateValue(value: string): Date | undefined {
const iso = toISODate(value)
@@ -57,14 +57,13 @@ function AddBooleanInput({ value, locale, onChange }: { value: string; locale: A
function AddDateInput({
value,
locale,
- dateDisplayFormat,
onChange,
}: {
value: string
locale: AppLocale
- dateDisplayFormat: DateDisplayFormat
onChange: (v: string) => void
}) {
+ const dateDisplayFormat = useDateDisplayFormat()
const selectedDate = value ? parseDateValue(value) : undefined
const formatted = value ? formatDateValue(value, dateDisplayFormat) : ''
return (
@@ -134,17 +133,16 @@ function AddNumberInput({ value, onChange, onKeyDown }: {
)
}
-function AddPropertyValueInput({ displayMode, value, onChange, onKeyDown, vaultStatuses, locale, dateDisplayFormat }: {
+function AddPropertyValueInput({ displayMode, value, onChange, onKeyDown, vaultStatuses, locale }: {
displayMode: PropertyDisplayMode; value: string; onChange: (v: string) => void
onKeyDown: (e: React.KeyboardEvent) => void; vaultStatuses: string[]
locale: AppLocale
- dateDisplayFormat: DateDisplayFormat
}) {
switch (displayMode) {
case 'number':
return
case 'boolean': return
- case 'date': return
+ case 'date': return
case 'status': return
case 'tags': return (
void; onCancel: () => void
vaultStatuses: string[]
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}) {
const [newKey, setNewKey] = useState('')
const [newValue, setNewValue] = useState('')
@@ -209,7 +206,7 @@ export function AddPropertyForm({ onAdd, onCancel, vaultStatuses, locale = 'en',
})}
-
+
onAdd(newKey, newValue, displayMode)}
disabled={!canSubmit} title={translate(locale, 'inspector.properties.addProperty')}
diff --git a/src/components/DynamicPropertiesPanel.tsx b/src/components/DynamicPropertiesPanel.tsx
index 70423533..7f86959b 100644
--- a/src/components/DynamicPropertiesPanel.tsx
+++ b/src/components/DynamicPropertiesPanel.tsx
@@ -24,7 +24,6 @@ import {
import { humanizePropertyKey } from '../utils/propertyLabels'
import { translate, type AppLocale } from '../lib/i18n'
import { canonicalSystemMetadataKey, hasSystemMetadataKey } from '../utils/systemMetadata'
-import { DEFAULT_DATE_DISPLAY_FORMAT, type DateDisplayFormat } from '../utils/dateDisplay'
// eslint-disable-next-line react-refresh/only-export-components -- utility co-located with component
export function containsWikilinks(value: FrontmatterValue): boolean {
@@ -35,11 +34,10 @@ export function containsWikilinks(value: FrontmatterValue): boolean {
const PROPERTY_ROW_CLASS_NAME = 'group/prop grid min-h-7 min-w-0 grid-cols-2 items-center gap-2 rounded px-1.5 outline-none transition-colors hover:bg-muted focus:bg-muted focus:ring-1 focus:ring-primary'
-function PropertyRow({ propKey, value, editingKey, displayMode, autoMode, vaultStatuses, vaultTags, dateDisplayFormat, locale, onStartEdit, onSave, onSaveList, onUpdate, onDelete, onDisplayModeChange }: {
+function PropertyRow({ propKey, value, editingKey, displayMode, autoMode, vaultStatuses, vaultTags, locale, onStartEdit, onSave, onSaveList, onUpdate, onDelete, onDisplayModeChange }: {
propKey: string; value: FrontmatterValue; editingKey: string | null
displayMode: PropertyDisplayMode; autoMode: PropertyDisplayMode
vaultStatuses: string[]; vaultTags: string[]
- dateDisplayFormat: DateDisplayFormat
onStartEdit: (key: string | null) => void; onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void
onUpdate?: (key: string, value: FrontmatterValue) => void; onDelete?: (key: string) => void
@@ -66,7 +64,7 @@ function PropertyRow({ propKey, value, editingKey, displayMode, autoMode, vaultS
)}
-
+
)
@@ -163,7 +161,6 @@ function TypeDerivedPropertySlot({
autoMode,
vaultStatuses,
vaultTags,
- dateDisplayFormat,
onStartEdit,
onSave,
onSaveList,
@@ -177,7 +174,6 @@ function TypeDerivedPropertySlot({
autoMode: PropertyDisplayMode
vaultStatuses: string[]
vaultTags: string[]
- dateDisplayFormat: DateDisplayFormat
onStartEdit: (key: string | null) => void
onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void
@@ -195,7 +191,6 @@ function TypeDerivedPropertySlot({
autoMode={autoMode}
vaultStatuses={vaultStatuses}
vaultTags={vaultTags}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={onStartEdit}
onSave={onSave}
onSaveList={onSaveList}
@@ -320,7 +315,6 @@ function PropertyEntryRows({
vaultStatuses,
vaultTagsByKey,
locale,
- dateDisplayFormat,
onStartEdit,
onSave,
onSaveList,
@@ -335,7 +329,6 @@ function PropertyEntryRows({
vaultStatuses: string[]
vaultTagsByKey: Record
locale: AppLocale
- dateDisplayFormat: DateDisplayFormat
onStartEdit: (key: string | null) => void
onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void
@@ -355,7 +348,6 @@ function PropertyEntryRows({
autoMode={detectPropertyType(key, value)}
vaultStatuses={vaultStatuses}
vaultTags={(Reflect.get(vaultTagsByKey, key) as string[] | undefined) ?? []}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={onStartEdit}
onSave={onSave}
onSaveList={onSaveList}
@@ -369,7 +361,6 @@ function PropertyEntryRows({
editingKey={editingKey} displayMode={getEffectiveDisplayMode(key, value, displayOverrides)} autoMode={detectPropertyType(key, value)}
vaultStatuses={vaultStatuses}
vaultTags={(Reflect.get(vaultTagsByKey, key) as string[] | undefined) ?? []}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={onStartEdit} onSave={onSave}
onSaveList={onSaveList} onUpdate={onUpdate}
onDelete={onDelete}
@@ -388,7 +379,6 @@ function PendingSuggestedPropertyRow({
vaultStatuses,
vaultTagsByKey,
locale,
- dateDisplayFormat,
onStartEdit,
onSave,
onSaveList,
@@ -399,7 +389,6 @@ function PendingSuggestedPropertyRow({
vaultStatuses: string[]
vaultTagsByKey: Record
locale: AppLocale
- dateDisplayFormat: DateDisplayFormat
onStartEdit: (key: string | null) => void
onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void
@@ -419,7 +408,6 @@ function PendingSuggestedPropertyRow({
autoMode={getSuggestedDisplayMode(pendingSuggestedKey)}
vaultStatuses={vaultStatuses}
vaultTags={(Reflect.get(vaultTagsByKey, pendingSuggestedKey) as string[] | undefined) ?? []}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={onStartEdit}
onSave={onSave}
onSaveList={onSaveList}
@@ -511,7 +499,6 @@ function DynamicPropertiesPanelContent({
pendingSuggestedKey,
missingSuggested,
missingTypeName,
- dateDisplayFormat,
locale,
workspaces,
onUpdateProperty,
@@ -529,7 +516,6 @@ function DynamicPropertiesPanelContent({
pendingSuggestedKey: string | null
missingSuggested: Array<{ key: string; label: string }>
missingTypeName: string | null
- dateDisplayFormat: DateDisplayFormat
locale: AppLocale
workspaces?: WorkspaceIdentity[]
onUpdateProperty?: (key: string, value: FrontmatterValue) => void
@@ -573,7 +559,6 @@ function DynamicPropertiesPanelContent({
vaultStatuses={vaultStatuses}
vaultTagsByKey={vaultTagsByKey}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={setEditingKey}
onSave={handleSaveValue}
onSaveList={handleSaveList}
@@ -589,7 +574,6 @@ function DynamicPropertiesPanelContent({
vaultStatuses={vaultStatuses}
vaultTagsByKey={vaultTagsByKey}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={setEditingKey}
onSave={handleSaveTypeDerivedValue}
onSaveList={handleSaveList}
@@ -602,7 +586,6 @@ function DynamicPropertiesPanelContent({
vaultStatuses={vaultStatuses}
vaultTagsByKey={vaultTagsByKey}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
onStartEdit={onStartPendingSuggestedEdit}
onSave={onSaveSuggestedValue}
onSaveList={handleSaveList}
@@ -623,7 +606,6 @@ function DynamicPropertiesPanelContent({
onCancel={() => setShowAddDialog(false)}
vaultStatuses={vaultStatuses}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
)}
@@ -643,7 +625,6 @@ interface DynamicPropertiesPanelProps {
onCreateMissingType?: (typeName: string) => boolean | void | Promise
onChangeWorkspace?: (workspace: WorkspaceIdentity) => void | Promise
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}
export function DynamicPropertiesPanel({
@@ -651,7 +632,6 @@ export function DynamicPropertiesPanel({
onUpdateProperty, onDeleteProperty, onAddProperty, onNavigate, onCreateMissingType,
onChangeWorkspace, workspaces,
locale = 'en',
- dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT,
}: DynamicPropertiesPanelProps) {
const propertyState = usePropertyPanelState({ entries, entryIsA: entry.isA, frontmatter, onUpdateProperty, onDeleteProperty, onAddProperty })
const [pendingSuggestedKey, setPendingSuggestedKey] = useState(null)
@@ -684,7 +664,6 @@ export function DynamicPropertiesPanel({
pendingSuggestedKey={pendingSuggestedKey}
missingSuggested={missingSuggested}
missingTypeName={missingTypeName}
- dateDisplayFormat={dateDisplayFormat}
locale={locale}
workspaces={workspaces}
onUpdateProperty={onUpdateProperty}
diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx
index e82003d5..026e7279 100644
--- a/src/components/Editor.tsx
+++ b/src/components/Editor.tsx
@@ -10,7 +10,6 @@ import { translate, type AppLocale } from '../lib/i18n'
import { RUNTIME_STYLE_NONCE } from '../lib/runtimeStyleNonce'
import type { VaultEntry, GitCommit, NoteWidthMode, NoteStatus, WorkspaceIdentity } from '../types'
import type { NoteListItem } from '../utils/ai-context'
-import type { DateDisplayFormat } from '../utils/dateDisplay'
import type { FrontmatterValue } from './Inspector'
import type { FrontmatterOpOptions } from '../hooks/frontmatterOps'
import { ResizeHandle } from './ResizeHandle'
@@ -124,7 +123,6 @@ interface EditorProps {
/** Registers a hook that flushes the raw editor buffer into app state before external actions. */
flushPendingRawContentRef?: React.MutableRefObject<((path: string) => void) | null>
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}
function useEditorModeExclusion({
@@ -389,7 +387,6 @@ function EditorLayout({
workspaces,
onUnsupportedAiPaste,
locale,
- dateDisplayFormat,
}: {
tabs: Tab[]
activeTabPath: string | null
@@ -461,7 +458,6 @@ function EditorLayout({
workspaces?: WorkspaceIdentity[]
onUnsupportedAiPaste?: (message: string) => void
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}) {
const activeBinaryTab = activeTab?.entry.fileKind === 'binary' ? activeTab : null
const showEmptyState = tabs.length === 0 && activeTabPath === null && !isVaultLoading
@@ -565,7 +561,6 @@ function EditorLayout({
onVaultChanged={onVaultChanged}
workspaces={workspaces}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
diff --git a/src/components/EditorRightPanel.tsx b/src/components/EditorRightPanel.tsx
index 3be33300..b7271fa3 100644
--- a/src/components/EditorRightPanel.tsx
+++ b/src/components/EditorRightPanel.tsx
@@ -5,7 +5,6 @@ import type { AiTarget } from '../lib/aiTargets'
import type { AppLocale } from '../lib/i18n'
import type { VaultEntry, GitCommit, WorkspaceIdentity } from '../types'
import type { NoteListItem } from '../utils/ai-context'
-import type { DateDisplayFormat } from '../utils/dateDisplay'
import { Inspector, type FrontmatterValue } from './Inspector'
import type { FrontmatterOpOptions } from '../hooks/frontmatterOps'
import { AiPanelView } from './AiPanel'
@@ -51,7 +50,6 @@ interface EditorRightPanelProps {
onVaultChanged?: () => void
workspaces?: WorkspaceIdentity[]
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}
type AiPanelSectionProps = Pick<
@@ -163,7 +161,6 @@ export function EditorRightPanel({
onFileCreated, onFileModified, onVaultChanged,
workspaces,
locale,
- dateDisplayFormat,
}: EditorRightPanelProps) {
if (!inspectorCollapsed) {
return (
@@ -191,7 +188,6 @@ export function EditorRightPanel({
onToggleRawEditor={onToggleRawEditor}
workspaces={workspaces}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
)
@@ -207,7 +203,6 @@ export function EditorRightPanel({
editor={editor}
entry={inspectorEntry}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
onClose={() => onToggleTableOfContents?.()}
sourceContent={inspectorContent}
/>
diff --git a/src/components/Inspector.tsx b/src/components/Inspector.tsx
index 2c910112..8ea57394 100644
--- a/src/components/Inspector.tsx
+++ b/src/components/Inspector.tsx
@@ -18,7 +18,6 @@ import { EmptyInspector, InitializePropertiesPrompt, InspectorHeader, InvalidFro
import { useBacklinks, useReferencedBy } from './inspector/useInspectorData'
import { useInspectorPropertyActions } from './inspector/useInspectorPropertyActions'
import type { AppLocale } from '../lib/i18n'
-import type { DateDisplayFormat } from '../utils/dateDisplay'
export type FrontmatterValue = string | number | boolean | string[] | null
@@ -42,7 +41,6 @@ interface InspectorProps {
onToggleRawEditor?: () => void
workspaces?: WorkspaceIdentity[]
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}
function buildTypeEntryMap(entries: VaultEntry[]): Record {
@@ -73,7 +71,6 @@ function ValidFrontmatterPanels({
onChangeWorkspace,
workspaces,
locale,
- dateDisplayFormat,
}: {
entry: VaultEntry
entries: VaultEntry[]
@@ -90,7 +87,6 @@ function ValidFrontmatterPanels({
onChangeWorkspace?: (entry: VaultEntry, workspace: WorkspaceIdentity) => Promise | void
workspaces?: WorkspaceIdentity[]
locale: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}) {
return (
<>
@@ -106,7 +102,6 @@ function ValidFrontmatterPanels({
onChangeWorkspace={onChangeWorkspace ? (workspace) => onChangeWorkspace(entry, workspace) : undefined}
workspaces={workspaces}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
@@ -167,7 +161,6 @@ function PrimaryInspectorPanel({
onChangeWorkspace?: (entry: VaultEntry, workspace: WorkspaceIdentity) => Promise | void
workspaces?: WorkspaceIdentity[]
locale: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}) {
if (frontmatterState === 'valid') {
return (
@@ -187,7 +180,6 @@ function PrimaryInspectorPanel({
onChangeWorkspace={onChangeWorkspace}
workspaces={workspaces}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
)
}
@@ -217,7 +209,6 @@ function InspectorBody({
onToggleRawEditor,
workspaces,
locale = 'en',
- dateDisplayFormat,
}: Omit) {
const referencedBy = useReferencedBy(entry, entries)
const backlinks = useBacklinks(entry, entries, referencedBy)
@@ -263,13 +254,12 @@ function InspectorBody({
onChangeWorkspace={onChangeWorkspace}
workspaces={workspaces}
locale={locale}
- dateDisplayFormat={dateDisplayFormat}
/>
)}
{backlinks.length > 0 && }
-
+
{gitHistory.length > 0 && }
>
diff --git a/src/components/NoteItem.tsx b/src/components/NoteItem.tsx
index a43db782..9436b018 100644
--- a/src/components/NoteItem.tsx
+++ b/src/components/NoteItem.tsx
@@ -9,13 +9,14 @@ import {
import { getTypeColor, getTypeLightColor } from '../utils/typeColors'
import { resolveIcon } from '../utils/iconRegistry'
import { getDisplayDate } from '../utils/noteListHelpers'
-import { DEFAULT_DATE_DISPLAY_FORMAT, formatTimestampForDateDisplay, type DateDisplayFormat } from '../utils/dateDisplay'
+import { formatTimestampForDateDisplay } from '../utils/dateDisplay'
import { filePreviewKind, type FilePreviewKind } from '../utils/filePreview'
import { NoteTitleIcon } from './NoteTitleIcon'
import { PropertyChips } from './note-item/PropertyChips'
import { ChangeNoteContent } from './note-item/ChangeNoteContent'
import { workspaceForEntry } from '../utils/workspaces'
import { WorkspaceInitialsBadge } from './WorkspaceInitialsBadge'
+import { useDateDisplayFormat } from '../hooks/useAppPreferences'
const TYPE_ICON_MAP: Record>> = {
Project: Wrench,
@@ -158,14 +159,12 @@ function NotePropertySection({
displayProps,
allEntries,
typeEntryMap,
- dateDisplayFormat,
onClickNote,
}: {
entry: VaultEntry
displayProps: string[]
allEntries: VaultEntry[]
typeEntryMap: Record
- dateDisplayFormat: DateDisplayFormat
onClickNote: NoteItemProps['onClickNote']
}) {
if (displayProps.length === 0) return null
@@ -176,7 +175,6 @@ function NotePropertySection({
displayProps={displayProps}
allEntries={allEntries}
typeEntryMap={typeEntryMap}
- dateDisplayFormat={dateDisplayFormat}
onOpenNote={onClickNote}
/>
)
@@ -189,7 +187,6 @@ function InteractiveNoteDetails({
displayProps,
allEntries,
typeEntryMap,
- dateDisplayFormat,
onClickNote,
}: {
entry: VaultEntry
@@ -198,7 +195,6 @@ function InteractiveNoteDetails({
displayProps: string[]
allEntries: VaultEntry[]
typeEntryMap: Record
- dateDisplayFormat: DateDisplayFormat
onClickNote: NoteItemProps['onClickNote']
}) {
return (
@@ -215,10 +211,9 @@ function InteractiveNoteDetails({
displayProps={displayProps}
allEntries={allEntries}
typeEntryMap={typeEntryMap}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={onClickNote}
/>
-
+
>
)
}
@@ -243,7 +238,6 @@ function StandardNoteContent({
displayProps,
allEntries,
typeEntryMap,
- dateDisplayFormat,
onClickNote,
}: {
entry: VaultEntry
@@ -255,7 +249,6 @@ function StandardNoteContent({
displayProps: string[]
allEntries: VaultEntry[]
typeEntryMap: Record
- dateDisplayFormat: DateDisplayFormat
onClickNote: NoteItemProps['onClickNote']
}) {
const te = typeEntryMap[entry.isA ?? '']
@@ -281,7 +274,6 @@ function StandardNoteContent({
displayProps={displayProps}
allEntries={allEntries}
typeEntryMap={typeEntryMap}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={onClickNote}
/>
)}
@@ -317,12 +309,11 @@ function NoteTitleRow({
function NoteDateRow({
entry,
allEntries,
- dateDisplayFormat,
}: {
entry: VaultEntry
allEntries: VaultEntry[]
- dateDisplayFormat: DateDisplayFormat
}) {
+ const dateDisplayFormat = useDateDisplayFormat()
const modifiedLabel = formatTimestampForDateDisplay(getDisplayDate(entry), dateDisplayFormat)
const createdLabel = entry.createdAt ? `Created ${formatTimestampForDateDisplay(entry.createdAt, dateDisplayFormat)}` : null
@@ -368,7 +359,6 @@ type NoteItemProps = {
typeEntryMap: Record
allEntries?: VaultEntry[]
displayPropsOverride?: string[] | null
- dateDisplayFormat?: DateDisplayFormat
onClickNote: (entry: VaultEntry, e: ReactMouseEvent) => void
onPrefetch?: (entry: VaultEntry) => void
onContextMenu?: (entry: VaultEntry, e: ReactMouseEvent) => void
@@ -501,7 +491,6 @@ function NoteItemContent({
displayProps,
allEntries,
typeEntryMap,
- dateDisplayFormat,
onClickNote,
}: {
entry: VaultEntry
@@ -514,7 +503,6 @@ function NoteItemContent({
displayProps: string[]
allEntries: VaultEntry[]
typeEntryMap: Record
- dateDisplayFormat: DateDisplayFormat
onClickNote: NoteItemProps['onClickNote']
}) {
if (changeStatus) {
@@ -539,13 +527,12 @@ function NoteItemContent({
displayProps={displayProps}
allEntries={allEntries}
typeEntryMap={typeEntryMap}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={onClickNote}
/>
)
}
-export function NoteItem({ entry, isSelected, isMultiSelected = false, isHighlighted = false, noteStatus = 'clean', changeStatus, typeEntryMap, allEntries, displayPropsOverride, dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT, onClickNote, onPrefetch, onContextMenu }: NoteItemProps) {
+export function NoteItem({ entry, isSelected, isMultiSelected = false, isHighlighted = false, noteStatus = 'clean', changeStatus, typeEntryMap, allEntries, displayPropsOverride, onClickNote, onPrefetch, onContextMenu }: NoteItemProps) {
const isBinary = entry.fileKind === 'binary'
const previewKind = filePreviewKind(entry)
const isPreviewableFile = previewKind !== null
@@ -586,7 +573,6 @@ export function NoteItem({ entry, isSelected, isMultiSelected = false, isHighlig
displayProps={displayProps}
allEntries={allEntries ?? [entry]}
typeEntryMap={typeEntryMap}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={onClickNote}
/>
diff --git a/src/components/NoteList.rendering.test.tsx b/src/components/NoteList.rendering.test.tsx
index 280c6478..1a0349e1 100644
--- a/src/components/NoteList.rendering.test.tsx
+++ b/src/components/NoteList.rendering.test.tsx
@@ -3,6 +3,7 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { NoteList } from './NoteList'
import { openNoteListPropertiesPicker } from './note-list/noteListPropertiesEvents'
+import { AppPreferencesProvider } from '../hooks/useAppPreferences'
import {
allSelection,
buildNoteListProps,
@@ -656,11 +657,15 @@ describe('NoteList rendering', () => {
})
it('formats date properties in note-list chips with the selected display format', async () => {
- renderNoteList({
+ const built = buildNoteListProps({
entries: makeBookTypeEntries(['Due'], { properties: { Due: '2026-05-11' } }),
selection: { kind: 'sectionGroup', type: 'Book' },
- dateDisplayFormat: 'european',
})
+ render(
+
+
+ ,
+ )
expect(screen.getByTestId('property-chip-due-0')).toHaveTextContent('11/5/2026')
diff --git a/src/components/PropertyValueCells.test.tsx b/src/components/PropertyValueCells.test.tsx
index d881c985..984c506d 100644
--- a/src/components/PropertyValueCells.test.tsx
+++ b/src/components/PropertyValueCells.test.tsx
@@ -115,6 +115,7 @@ vi.mock('@/components/ui/popover', () => ({
}))
import { DisplayModeSelector, SmartPropertyValueCell } from './PropertyValueCells'
+import { AppPreferencesProvider } from '../hooks/useAppPreferences'
describe('PropertyValueCells', () => {
it('shows the relationship icon and resets to auto mode when the auto option is selected', () => {
@@ -265,18 +266,19 @@ describe('PropertyValueCells', () => {
expect(onStartEdit).toHaveBeenCalledWith(null)
rerender(
- ,
+
+
+ ,
)
expect(screen.getByTestId('date-display')).toHaveTextContent('20/4/2026')
diff --git a/src/components/PropertyValueCells.tsx b/src/components/PropertyValueCells.tsx
index 201a63e8..8d9b8117 100644
--- a/src/components/PropertyValueCells.tsx
+++ b/src/components/PropertyValueCells.tsx
@@ -11,7 +11,6 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
import { XIcon } from 'lucide-react'
import { trackDatePropertyDirectEntrySaved } from '../lib/productAnalytics'
import { translate, type AppLocale } from '../lib/i18n'
-import { DEFAULT_DATE_DISPLAY_FORMAT, type DateDisplayFormat } from '../utils/dateDisplay'
import { isValidCssColor } from '../utils/colorUtils'
import {
type PropertyDisplayMode,
@@ -28,6 +27,7 @@ import { ColorEditableValue } from './ColorInput'
import { IconEditableValue } from './IconEditableValue'
import { PROPERTY_CHIP_STYLE } from './propertyChipStyles'
import { canonicalSystemMetadataKey } from '../utils/systemMetadata'
+import { useDateDisplayFormat } from '../hooks/useAppPreferences'
const ISO_DATE_INPUT_RE = /^(\d{4})-(\d{2})-(\d{2})$/
const DEFAULT_DATE_PICKER_START_YEAR = 1800
@@ -275,14 +275,14 @@ function NumberValue({
)
}
-function DateValue({ value, onSave, locale = 'en', dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT, autoOpen = false, onCancel }: {
+function DateValue({ value, onSave, locale = 'en', autoOpen = false, onCancel }: {
value: string
onSave: (newValue: string) => void
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
autoOpen?: boolean
onCancel?: () => void
}) {
+ const dateDisplayFormat = useDateDisplayFormat()
const [open, setOpen] = useState(autoOpen)
const formatted = formatDateValue(value, dateDisplayFormat)
const pickDateLabel = translate(locale, 'inspector.properties.pickDate')
@@ -522,7 +522,6 @@ function autoDetectFromValue(propKey: string, value: FrontmatterValue): Property
type SmartCellProps = {
propKey: string; value: FrontmatterValue; displayMode: PropertyDisplayMode; isEditing: boolean
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
vaultStatuses: string[]; vaultTags: string[]
onStartEdit: (key: string | null) => void; onSave: (key: string, value: string) => void
onSaveList: (key: string, items: string[]) => void; onUpdate?: (key: string, value: FrontmatterValue) => void
@@ -590,7 +589,6 @@ const SCALAR_DISPLAY_RENDERERS: readonly [PropertyDisplayMode, ScalarDisplayRend
key={`${props.propKey}:${props.isEditing ? 'editing' : 'view'}`}
value={String(props.value ?? '')}
locale={props.locale}
- dateDisplayFormat={props.dateDisplayFormat}
onSave={(nextValue) => props.onSave(props.propKey, nextValue)}
autoOpen={props.isEditing}
onCancel={() => props.onStartEdit(null)}
diff --git a/src/components/SearchPanel.tsx b/src/components/SearchPanel.tsx
index cd437c0c..fcd81b12 100644
--- a/src/components/SearchPanel.tsx
+++ b/src/components/SearchPanel.tsx
@@ -4,11 +4,12 @@ import type { SearchResult, VaultEntry } from '../types'
import { useUnifiedSearch } from '../hooks/useUnifiedSearch'
import { getTypeColor, buildTypeEntryMap } from '../utils/typeColors'
import { formatSearchSubtitle } from '../utils/noteListHelpers'
-import { DEFAULT_DATE_DISPLAY_FORMAT, type DateDisplayFormat } from '../utils/dateDisplay'
+import type { DateDisplayFormat } from '../utils/dateDisplay'
import { scrollSelectedHTMLChildIntoView } from '../utils/domScroll'
import { getTypeIcon } from './NoteItem'
import { NoteTitleIcon } from './NoteTitleIcon'
import { WorkspaceInitialsBadge } from './WorkspaceInitialsBadge'
+import { useDateDisplayFormat } from '../hooks/useAppPreferences'
interface SearchPanelProps {
open: boolean
@@ -16,7 +17,6 @@ interface SearchPanelProps {
entries: VaultEntry[]
onSelectNote: (entry: VaultEntry) => void
onClose: () => void
- dateDisplayFormat?: DateDisplayFormat
}
type SearchKeyboardAction = 'close' | 'next' | 'previous' | 'select'
@@ -182,8 +182,8 @@ export function SearchPanel({
entries,
onSelectNote,
onClose,
- dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT,
}: SearchPanelProps) {
+ const dateDisplayFormat = useDateDisplayFormat()
const {
elapsedMs,
entryLookup,
@@ -332,11 +332,23 @@ function resolveSearchResultPresentation({
noteType,
subtitle: entry ? formatSearchSubtitle(entry, dateDisplayFormat) : null,
title: entry?.title ?? result.title,
- typeColor: noteType ? getTypeColor(isA, typeEntry?.color) : undefined,
- workspace: showWorkspace ? entry?.workspace ?? null : null,
+ typeColor: resolveSearchResultTypeColor(noteType, isA, typeEntry),
+ workspace: resolveSearchResultWorkspace(showWorkspace, entry),
}
}
+function resolveSearchResultTypeColor(
+ noteType: string | null,
+ isA: string | null,
+ typeEntry: VaultEntry | undefined,
+): string | undefined {
+ return noteType ? getTypeColor(isA, typeEntry?.color) : undefined
+}
+
+function resolveSearchResultWorkspace(showWorkspace: boolean, entry: VaultEntry | undefined): VaultEntry['workspace'] | null {
+ return showWorkspace ? entry?.workspace ?? null : null
+}
+
function SearchResultRow({
result, entry, selected, index, typeEntryMap, showWorkspace, dateDisplayFormat, onSelect, onHover,
}: SearchResultRowProps) {
diff --git a/src/components/TableOfContentsPanel.tsx b/src/components/TableOfContentsPanel.tsx
index b1e404e6..7e3be687 100644
--- a/src/components/TableOfContentsPanel.tsx
+++ b/src/components/TableOfContentsPanel.tsx
@@ -17,7 +17,6 @@ import {
getFolderDepthIndent,
} from './folder-tree/folderTreeLayout'
import { NoteInfoPanel } from './inspector/NoteInfoPanel'
-import type { DateDisplayFormat } from '../utils/dateDisplay'
interface TableOfContentsEditor {
document?: unknown[]
@@ -29,7 +28,6 @@ interface TableOfContentsPanelProps {
editor: TableOfContentsEditor
entry: VaultEntry | null
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
onClose: () => void
sourceContent?: string | null
}
@@ -261,7 +259,6 @@ export const TableOfContentsPanel = memo(function TableOfContentsPanel({
editor,
entry,
locale = 'en',
- dateDisplayFormat,
onClose,
sourceContent,
}: TableOfContentsPanelProps) {
@@ -289,7 +286,7 @@ export const TableOfContentsPanel = memo(function TableOfContentsPanel({
{entry && (
-
+
)}
diff --git a/src/components/dateDisplayPreferenceFlow.test.tsx b/src/components/dateDisplayPreferenceFlow.test.tsx
new file mode 100644
index 00000000..8bd6f12a
--- /dev/null
+++ b/src/components/dateDisplayPreferenceFlow.test.tsx
@@ -0,0 +1,64 @@
+import type { ReactElement } from 'react'
+import { render, screen } from '@testing-library/react'
+import { describe, expect, it, vi } from 'vitest'
+import { TooltipProvider } from '@/components/ui/tooltip'
+import { AppPreferencesProvider } from '../hooks/useAppPreferences'
+import { NoteList } from './NoteList'
+import { SmartPropertyValueCell } from './PropertyValueCells'
+import {
+ buildNoteListProps,
+ makeEntry,
+ makeTypeDefinition,
+} from '../test-utils/noteListTestUtils'
+
+function renderWithPreferences(ui: ReactElement) {
+ return render(
+
+
+ {ui}
+
+ ,
+ )
+}
+
+describe('date display preference flow', () => {
+ it('formats note-list date chips from the shared preference provider', () => {
+ const entries = [
+ makeTypeDefinition('Book', ['Due']),
+ makeEntry({
+ path: '/vault/book.md',
+ filename: 'book.md',
+ title: 'Book Note',
+ isA: 'Book',
+ properties: { Due: '2026-05-11' },
+ }),
+ ]
+ const { props } = buildNoteListProps({
+ entries,
+ selection: { kind: 'sectionGroup', type: 'Book' },
+ })
+
+ renderWithPreferences( )
+
+ expect(screen.getByTestId('property-chip-due-0')).toHaveTextContent('11/5/2026')
+ })
+
+ it('keeps date editor input ISO while display text follows the shared preference', () => {
+ renderWithPreferences(
+ ,
+ )
+
+ expect(screen.getByTestId('date-display')).toHaveTextContent('20/4/2026')
+ expect(screen.getByTestId('date-picker-input')).toHaveValue('2026-04-20')
+ })
+})
diff --git a/src/components/inspector/NoteInfoPanel.tsx b/src/components/inspector/NoteInfoPanel.tsx
index e9a0d067..0f2f6574 100644
--- a/src/components/inspector/NoteInfoPanel.tsx
+++ b/src/components/inspector/NoteInfoPanel.tsx
@@ -3,10 +3,10 @@ import { Info } from '@phosphor-icons/react'
import { countWords } from '../../utils/wikilinks'
import { translate, type AppLocale } from '../../lib/i18n'
import {
- DEFAULT_DATE_DISPLAY_FORMAT,
formatTimestampForDateDisplay,
type DateDisplayFormat,
} from '../../utils/dateDisplay'
+import { useDateDisplayFormat } from '../../hooks/useAppPreferences'
function formatDate(timestamp: number | null, dateDisplayFormat: DateDisplayFormat): string {
if (!timestamp) return '\u2014'
@@ -34,13 +34,12 @@ export function NoteInfoPanel({
entry,
content,
locale = 'en',
- dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT,
}: {
entry: VaultEntry
content: string | null
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}) {
+ const dateDisplayFormat = useDateDisplayFormat()
const wordCount = countWords(content ?? '')
return (
diff --git a/src/components/note-item/PropertyChips.tsx b/src/components/note-item/PropertyChips.tsx
index 94e6968a..16620539 100644
--- a/src/components/note-item/PropertyChips.tsx
+++ b/src/components/note-item/PropertyChips.tsx
@@ -2,7 +2,7 @@ import { createElement, useMemo, useState, type ComponentType, type MouseEvent,
import { Link } from '@phosphor-icons/react'
import { cn } from '@/lib/utils'
import type { VaultEntry } from '../../types'
-import { DEFAULT_DATE_DISPLAY_FORMAT, type DateDisplayFormat } from '../../utils/dateDisplay'
+import { useDateDisplayFormat } from '../../hooks/useAppPreferences'
import { resolveNoteIcon } from '../../utils/noteIcon'
import { openExternalUrl } from '../../utils/url'
import { resolvePropertyChipValues, type PropertyChipValue } from './propertyChipValues'
@@ -96,16 +96,15 @@ export function PropertyChips({
displayProps,
allEntries,
typeEntryMap,
- dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT,
onOpenNote,
}: {
entry: VaultEntry
displayProps: string[]
allEntries: VaultEntry[]
typeEntryMap: Record
- dateDisplayFormat?: DateDisplayFormat
onOpenNote: (entry: VaultEntry, event: MouseEvent) => void
}) {
+ const dateDisplayFormat = useDateDisplayFormat()
const chips = useMemo(() => {
const result: { key: string; values: PropertyChipValue[] }[] = []
for (const prop of displayProps) {
diff --git a/src/components/note-list/useNoteListModel.tsx b/src/components/note-list/useNoteListModel.tsx
index 445b7407..f3ebf13a 100644
--- a/src/components/note-list/useNoteListModel.tsx
+++ b/src/components/note-list/useNoteListModel.tsx
@@ -9,7 +9,6 @@ import type {
ViewFile,
} from '../../types'
import type { AppLocale } from '../../lib/i18n'
-import type { DateDisplayFormat } from '../../utils/dateDisplay'
import type { NoteListFilter } from '../../utils/noteListHelpers'
import { countByFilter, countAllByFilter, countAllNotesByFilter } from '../../utils/noteListHelpers'
import type { AllNotesFileVisibility } from '../../utils/allNotesFileVisibility'
@@ -32,6 +31,7 @@ import {
} from './noteListHooks'
import { useChangesContextMenu } from './NoteListChangesMenu'
import { addNoteListSearchToggleListener, dispatchNoteListSearchAvailability } from '../../utils/noteListSearchEvents'
+import { useDateDisplayFormat } from '../../hooks/useAppPreferences'
type EntitySelection = Extract
const LIKELY_NEXT_PRELOAD_LIMIT = 6
@@ -166,7 +166,6 @@ interface UseNoteListContentParams {
views?: ViewFile[]
visibleNotesRef?: React.MutableRefObject
allNotesFileVisibility?: AllNotesFileVisibility
- dateDisplayFormat?: DateDisplayFormat
}
function useNoteListContent({
@@ -189,8 +188,8 @@ function useNoteListContent({
views,
visibleNotesRef,
allNotesFileVisibility,
- dateDisplayFormat,
}: UseNoteListContentParams) {
+ const dateDisplayFormat = useDateDisplayFormat()
const subFilter = (selection.kind === 'sectionGroup' || selection.kind === 'folder')
? noteListFilter
: undefined
@@ -392,7 +391,6 @@ interface UseRenderItemParams {
selectedNotePath: string | null
typeEntryMap: Record
displayPropsOverride?: string[] | null
- dateDisplayFormat?: DateDisplayFormat
isChangesView: boolean
onDiscardFile?: (relativePath: string) => Promise
resolvedGetNoteStatus: (path: string) => NoteStatus
@@ -408,7 +406,6 @@ function useRenderItem({
selectedNotePath,
typeEntryMap,
displayPropsOverride,
- dateDisplayFormat,
isChangesView,
onDiscardFile,
resolvedGetNoteStatus,
@@ -433,7 +430,6 @@ function useRenderItem({
typeEntryMap={typeEntryMap}
allEntries={entries}
displayPropsOverride={displayPropsOverride}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={handleClickNote}
onContextMenu={contextMenuHandler}
/>
@@ -449,7 +445,6 @@ function useRenderItem({
typeEntryMap={typeEntryMap}
allEntries={entries}
displayPropsOverride={displayPropsOverride}
- dateDisplayFormat={dateDisplayFormat}
onClickNote={handleClickNote}
onPrefetch={prefetchNoteContent}
onContextMenu={contextMenuHandler}
@@ -457,7 +452,6 @@ function useRenderItem({
)
), [
contextMenuHandler,
- dateDisplayFormat,
displayPropsOverride,
entries,
getChangeStatus,
@@ -507,7 +501,6 @@ export interface NoteListProps {
visibleNotesRef?: React.MutableRefObject
allNotesFileVisibility?: AllNotesFileVisibility
locale?: AppLocale
- dateDisplayFormat?: DateDisplayFormat
}
function buildNoteListLayoutModel(params: {
@@ -627,7 +620,6 @@ export function useNoteListModel({
visibleNotesRef,
allNotesFileVisibility,
locale = 'en',
- dateDisplayFormat,
}: NoteListProps) {
const selectedNotePath = selectedNote?.path ?? null
const { modifiedPathSet, modifiedSuffixes, resolvedGetNoteStatus } = useModifiedFilesState(modifiedFiles, getNoteStatus)
@@ -653,7 +645,6 @@ export function useNoteListModel({
views,
visibleNotesRef,
allNotesFileVisibility,
- dateDisplayFormat,
})
const interaction = useNoteListInteractionState({
searched: content.searched,
@@ -683,7 +674,6 @@ export function useNoteListModel({
selectedNotePath,
typeEntryMap: content.typeEntryMap,
displayPropsOverride: content.displayPropsOverride,
- dateDisplayFormat,
isChangesView: selection.kind === 'filter' && selection.filter === 'changes',
onDiscardFile,
resolvedGetNoteStatus,
diff --git a/src/hooks/useAppPreferences.ts b/src/hooks/useAppPreferences.ts
index 259922f6..3c6e3323 100644
--- a/src/hooks/useAppPreferences.ts
+++ b/src/hooks/useAppPreferences.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo } from 'react'
+import { createContext, createElement, useCallback, useContext, useEffect, useMemo, type ReactNode } from 'react'
import type { Settings } from '../types'
import type { ThemeMode } from '../lib/themeMode'
import {
@@ -8,7 +8,7 @@ import {
serializeUiLanguagePreference,
type UiLanguagePreference,
} from '../lib/i18n'
-import { DEFAULT_DATE_DISPLAY_FORMAT, normalizeDateDisplayFormat } from '../utils/dateDisplay'
+import { DEFAULT_DATE_DISPLAY_FORMAT, normalizeDateDisplayFormat, type DateDisplayFormat } from '../utils/dateDisplay'
import { resolveAllNotesFileVisibility } from '../utils/allNotesFileVisibility'
import { useAiAgentPreferences } from './useAiAgentPreferences'
import type { AiAgentsStatus } from '../lib/aiAgents'
@@ -24,6 +24,31 @@ interface AppPreferencesConfig {
settingsLoaded: boolean
}
+interface AppPreferenceValues {
+ dateDisplayFormat: DateDisplayFormat
+}
+
+const DEFAULT_APP_PREFERENCES: AppPreferenceValues = {
+ dateDisplayFormat: DEFAULT_DATE_DISPLAY_FORMAT,
+}
+
+const AppPreferencesContext = createContext(DEFAULT_APP_PREFERENCES)
+
+export function AppPreferencesProvider({
+ children,
+ dateDisplayFormat = DEFAULT_DATE_DISPLAY_FORMAT,
+}: {
+ children: ReactNode
+ dateDisplayFormat?: DateDisplayFormat
+}) {
+ const value = useMemo(() => ({ dateDisplayFormat }), [dateDisplayFormat])
+ return createElement(AppPreferencesContext.Provider, { value }, children)
+}
+
+export function useDateDisplayFormat(): DateDisplayFormat {
+ return useContext(AppPreferencesContext).dateDisplayFormat
+}
+
export function useAppPreferences({
aiAgentsStatus,
onToast,