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

@@ -1,5 +1,11 @@
import { describe, expect, it } from 'vitest'
import { deriveDisplayTitleState, extractH1TitleFromContent, filenameStemToTitle } from './noteTitle'
import {
contentDefinesDisplayTitle,
deriveDisplayTitleState,
extractFrontmatterTitleFromContent,
extractH1TitleFromContent,
filenameStemToTitle,
} from './noteTitle'
describe('filenameStemToTitle', () => {
it('converts kebab-case filenames into title case', () => {
@@ -23,10 +29,32 @@ describe('extractH1TitleFromContent', () => {
})
})
describe('extractFrontmatterTitleFromContent', () => {
it('extracts the frontmatter title when present', () => {
const content = '---\ntitle: Legacy Title\nstatus: Active\n---\n## Body'
expect(extractFrontmatterTitleFromContent(content)).toBe('Legacy Title')
})
it('returns null when the frontmatter title is missing', () => {
expect(extractFrontmatterTitleFromContent('---\nstatus: Active\n---\n## Body')).toBeNull()
})
})
describe('contentDefinesDisplayTitle', () => {
it('returns true when the document title comes from frontmatter', () => {
const content = '---\ntitle: Spring 2026\n---\n## Goals'
expect(contentDefinesDisplayTitle(content)).toBe(true)
})
it('returns false when title still comes from the filename', () => {
expect(contentDefinesDisplayTitle('Body only')).toBe(false)
})
})
describe('deriveDisplayTitleState', () => {
it('prefers H1 over frontmatter title and filename', () => {
const content = '---\ntitle: Legacy Title\n---\n# Updated Title\n\nBody'
expect(deriveDisplayTitleState(content, 'legacy-title.md', 'Legacy Title')).toEqual({
expect(deriveDisplayTitleState({ content, filename: 'legacy-title.md', frontmatterTitle: 'Legacy Title' })).toEqual({
title: 'Updated Title',
hasH1: true,
})
@@ -34,14 +62,22 @@ describe('deriveDisplayTitleState', () => {
it('falls back to frontmatter title when no H1 is present', () => {
const content = '---\ntitle: Legacy Title\n---\nBody'
expect(deriveDisplayTitleState(content, 'legacy-title.md', 'Legacy Title')).toEqual({
expect(deriveDisplayTitleState({ content, filename: 'legacy-title.md', frontmatterTitle: 'Legacy Title' })).toEqual({
title: 'Legacy Title',
hasH1: false,
})
})
it('reads the frontmatter title from content when no explicit title is passed', () => {
const content = '---\ntitle: Spring 2026\n---\n## Goals'
expect(deriveDisplayTitleState({ content, filename: 'spring-2026.md' })).toEqual({
title: 'Spring 2026',
hasH1: false,
})
})
it('falls back to filename title when there is no H1 or frontmatter title', () => {
expect(deriveDisplayTitleState('Body only', 'renamed-note.md')).toEqual({
expect(deriveDisplayTitleState({ content: 'Body only', filename: 'renamed-note.md' })).toEqual({
title: 'Renamed Note',
hasH1: false,
})

View File

@@ -1,5 +1,22 @@
import { parseFrontmatter } from './frontmatter'
import { splitFrontmatter } from './wikilinks'
interface ResolvedContentTitle {
source: 'h1' | 'frontmatter'
title: string
}
interface DisplayTitleInput {
content: string
filename: string
frontmatterTitle?: string | null
}
interface DisplayTitleState {
title: string
hasH1: boolean
}
function replaceWikilinkAliases(text: string): string {
return text.replace(/\[\[[^|\]]+\|([^\]]+)\]\]/g, '$1')
}
@@ -49,20 +66,46 @@ export function extractH1TitleFromContent(content: string): string | null {
return null
}
export function deriveDisplayTitleState(
content: string,
filename: string,
frontmatterTitle?: string | null,
): { title: string, hasH1: boolean } {
export function extractFrontmatterTitleFromContent(content: string): string | null {
const title = parseFrontmatter(content).title
if (typeof title !== 'string') return null
const trimmed = title.trim()
return trimmed || null
}
function resolveContentTitle(content: string, frontmatterTitle?: string | null): ResolvedContentTitle | null {
const h1Title = extractH1TitleFromContent(content)
if (h1Title) {
return { title: h1Title, hasH1: true }
return { title: h1Title, source: 'h1' }
}
const trimmedFrontmatterTitle = frontmatterTitle?.trim()
if (trimmedFrontmatterTitle) {
return { title: trimmedFrontmatterTitle, hasH1: false }
const resolvedFrontmatterTitle = frontmatterTitle?.trim() || extractFrontmatterTitleFromContent(content)
if (resolvedFrontmatterTitle) {
return { title: resolvedFrontmatterTitle, source: 'frontmatter' }
}
return { title: filenameStemToTitle(filename), hasH1: false }
return null
}
export function contentDefinesDisplayTitle(content: string): boolean {
return resolveContentTitle(content) !== null
}
export function deriveDisplayTitleState({
content,
filename,
frontmatterTitle,
}: DisplayTitleInput): DisplayTitleState {
const resolvedTitle = resolveContentTitle(content, frontmatterTitle)
if (resolvedTitle) {
return {
title: resolvedTitle.title,
hasH1: resolvedTitle.source === 'h1',
}
}
return {
title: filenameStemToTitle(filename),
hasH1: false,
}
}