fix: hide legacy title chrome for frontmatter titles

This commit is contained in:
lucaronin
2026-04-09 12:51:06 +02:00
parent d13e181658
commit cb2e28f3d9
7 changed files with 199 additions and 31 deletions

View File

@@ -62,6 +62,26 @@ describe('deriveEditorContentState', () => {
content: '---\ntitle: Legacy Project\n---\nBody without a heading',
})
expect(state.hasH1).toBe(false)
expect(state.showTitleSection).toBe(false)
})
it('hides the legacy title section when a frontmatter title drives the display title', () => {
const state = deriveState({
entry: baseEntry,
content: '---\ntitle: Spring 2026\nstatus: Active\n---\n## Goals',
})
expect(state.hasH1).toBe(false)
expect(state.showTitleSection).toBe(false)
})
it('keeps the title section when the document title still comes from the filename', () => {
const state = deriveState({
entry: baseEntry,
content: '---\nstatus: Active\n---\nBody without a heading',
})
expect(state.hasH1).toBe(false)
expect(state.showTitleSection).toBe(true)
})

View File

@@ -1,5 +1,5 @@
import type { NoteStatus, VaultEntry } from '../../types'
import { extractH1TitleFromContent } from '../../utils/noteTitle'
import { contentDefinesDisplayTitle, extractH1TitleFromContent } from '../../utils/noteTitle'
import { countWords } from '../../utils/wikilinks'
export interface EditorContentTab {
@@ -14,6 +14,19 @@ interface EditorContentStateInput {
activeStatus: NoteStatus
}
interface TitleSectionState {
hasDisplayTitle: boolean
hasH1: boolean
}
interface VisibilityState {
effectiveRawMode: boolean
isDeletedPreview: boolean
isNonMarkdownText: boolean
showEditor: boolean
showTitleSection: boolean
}
export interface EditorContentState {
freshEntry: VaultEntry | undefined
isArchived: boolean
@@ -36,10 +49,53 @@ function contentHasTopLevelH1(activeTab: EditorContentTab | null): boolean {
return activeTab ? extractH1TitleFromContent(activeTab.content) !== null : false
}
function contentDefinesTitle(activeTab: EditorContentTab | null): boolean {
return activeTab ? contentDefinesDisplayTitle(activeTab.content) : false
}
function resolveHasH1(activeTab: EditorContentTab | null, freshEntry: VaultEntry | undefined): boolean {
return contentHasTopLevelH1(activeTab) || freshEntry?.hasH1 === true || activeTab?.entry.hasH1 === true
}
function resolveHasDisplayTitle(activeTab: EditorContentTab | null, hasH1: boolean): boolean {
return hasH1 || contentDefinesTitle(activeTab)
}
function deriveTitleSectionState(activeTab: EditorContentTab | null, freshEntry: VaultEntry | undefined): TitleSectionState {
const hasH1 = resolveHasH1(activeTab, freshEntry)
return {
hasDisplayTitle: resolveHasDisplayTitle(activeTab, hasH1),
hasH1,
}
}
function deriveVisibilityState(input: {
activeStatus: NoteStatus
activeTab: EditorContentTab | null
freshEntry: VaultEntry | undefined
hasDisplayTitle: boolean
rawMode: boolean
}): VisibilityState {
const {
activeStatus,
activeTab,
freshEntry,
hasDisplayTitle,
rawMode,
} = input
const isDeletedPreview = !!activeTab && !freshEntry
const isNonMarkdownText = activeTab?.entry.fileKind === 'text'
const effectiveRawMode = rawMode || isNonMarkdownText
return {
isDeletedPreview,
isNonMarkdownText,
effectiveRawMode,
showEditor: !effectiveRawMode,
showTitleSection: !isDeletedPreview && !hasDisplayTitle && !isUnsavedUntitledDraft(activeTab, activeStatus),
}
}
function isUnsavedUntitledDraft(activeTab: EditorContentTab | null, activeStatus: NoteStatus): boolean {
if (!activeTab) return false
if (!activeTab.entry.filename.startsWith('untitled-')) return false
@@ -53,22 +109,20 @@ export function deriveEditorContentState({
activeStatus,
}: EditorContentStateInput): EditorContentState {
const freshEntry = findFreshEntry(activeTab, entries)
const isDeletedPreview = !!activeTab && !freshEntry
const hasH1 = resolveHasH1(activeTab, freshEntry)
const isNonMarkdownText = activeTab?.entry.fileKind === 'text'
const effectiveRawMode = rawMode || isNonMarkdownText
const showEditor = !effectiveRawMode
const showTitleSection = !isDeletedPreview && !hasH1 && !isUnsavedUntitledDraft(activeTab, activeStatus)
const titleState = deriveTitleSectionState(activeTab, freshEntry)
const visibilityState = deriveVisibilityState({
activeStatus,
activeTab,
freshEntry,
hasDisplayTitle: titleState.hasDisplayTitle,
rawMode,
})
return {
freshEntry,
isArchived: freshEntry?.archived ?? activeTab?.entry.archived ?? false,
hasH1,
isDeletedPreview,
isNonMarkdownText,
effectiveRawMode,
showEditor,
showTitleSection,
hasH1: titleState.hasH1,
...visibilityState,
path: activeTab?.entry.path ?? '',
wordCount: activeTab ? countWords(activeTab.content) : 0,
}