Show markdown front-matter by default in the rich editor and preview (#8623)

Flip the default so the front-matter banner is visible unless the user
explicitly hides it. The per-file visibility map now stores only hide
overrides (false) instead of show overrides: read defaults resolve to
true, the setter writes false / deletes on show, session persistence
preserves the real value, and hydration keeps false entries while
dropping legacy true entries back to the visible default.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-07-13 16:13:29 -07:00
committed by GitHub
co-authored by Orca
parent 833724830f
commit 398fc79c4f
8 changed files with 90 additions and 50 deletions
@@ -346,8 +346,9 @@ function EditorPanelInner({
activeMarkdownContent &&
extractFrontMatter(activeMarkdownContent)
)
// Why: front-matter shows by default; the map only carries per-file hide overrides.
const isMarkdownFrontmatterVisible =
markdownFrontmatterVisible[markdownDocumentStateFileId] ?? false
markdownFrontmatterVisible[markdownDocumentStateFileId] ?? true
const isMarkdownTableOfContentsVisible =
markdownTableOfContentsVisible[markdownDocumentStateFileId] ?? false
@@ -619,12 +619,11 @@ export default function MarkdownPreview({
.replace(/\r?\n(?:---|\+\+\+)\r?\n?$/, '')
.trim()
}, [frontMatter])
// Why: front matter is hidden by default (#4468) and controlled from the
// markdown preview actions menu, keeping metadata out of the reading surface
// unless the user explicitly asks for it.
// Why: front matter shows by default and is toggled off from the markdown
// preview actions menu; the store map only carries per-file hide overrides.
const toggleableSourceFileId: string | null = sourceFileId ?? null
const frontmatterVisible = toggleableSourceFileId
? (frontmatterVisibleByFile[toggleableSourceFileId] ?? false)
? (frontmatterVisibleByFile[toggleableSourceFileId] ?? true)
: true
const [activeAnnotationBlockKey, setActiveAnnotationBlockKey] = useState<string | null>(null)
const [reviewNotesCopied, setReviewNotesCopied] = useState(false)
@@ -176,18 +176,18 @@ describe('buildWorkspaceSessionPayload', () => {
expect(payload.browserTabsByWorktree?.['wt-1'][0].loading).toBe(false)
})
it('persists front-matter visibility only for restored editor files', () => {
it('persists front-matter hide overrides only for restored editor files', () => {
const payload = buildWorkspaceSessionPayload(
createSnapshot({
markdownFrontmatterVisible: {
'/tmp/demo.ts': true,
'/tmp/demo.diff': true,
'/tmp/closed.md': true
'/tmp/demo.ts': false,
'/tmp/demo.diff': false,
'/tmp/closed.md': false
}
})
)
expect(payload.markdownFrontmatterVisible).toEqual({ '/tmp/demo.ts': true })
expect(payload.markdownFrontmatterVisible).toEqual({ '/tmp/demo.ts': false })
})
it('does not persist empty split groups from transient simulator tab creation', () => {
+5 -3
View File
@@ -188,10 +188,12 @@ export function buildEditorSessionData(
WorkspaceVisibleTabType
>
const allEditFileIds = new Set(Object.values(editFileIdsByWorktree).flatMap((ids) => [...ids]))
// Why: preserve the actual value so per-file hide overrides survive restart;
// the map only ever carries `false` entries (visible is the default).
const persistedMarkdownFrontmatterVisible = Object.fromEntries(
Object.keys(markdownFrontmatterVisible ?? {})
.filter((fileId) => allEditFileIds.has(fileId))
.map((fileId) => [fileId, true])
Object.entries(markdownFrontmatterVisible ?? {}).filter(([fileId]) =>
allEditFileIds.has(fileId)
)
)
return {
+21 -21
View File
@@ -1482,7 +1482,7 @@ describe('createEditorSlice markdown view state', () => {
},
{ preview: true }
)
store.getState().setMarkdownFrontmatterVisible('/repo/docs/README.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/docs/README.md', false)
store.getState().setMarkdownTableOfContentsVisible('/repo/docs/README.md', true)
store.getState().openDiff('wt-1', '/repo/docs/guide.md', 'docs/guide.md', 'markdown', false, {
@@ -1512,7 +1512,7 @@ describe('createEditorSlice markdown view state', () => {
worktreeId: 'wt-1',
language: 'markdown'
})
store.getState().setMarkdownFrontmatterVisible('/repo/docs/README.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/docs/README.md', false)
store.getState().setMarkdownTableOfContentsVisible('/repo/docs/README.md', true)
store.getState().openDiff('wt-1', '/repo/docs/guide.md', 'docs/guide.md', 'markdown', false, {
@@ -1520,7 +1520,7 @@ describe('createEditorSlice markdown view state', () => {
})
expect(store.getState().markdownFrontmatterVisible).toEqual({
'/repo/docs/README.md': true
'/repo/docs/README.md': false
})
expect(store.getState().markdownTableOfContentsVisible).toEqual({
'/repo/docs/README.md': true
@@ -1573,28 +1573,28 @@ describe('createEditorSlice editor view mode', () => {
})
describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
it('stores visible=true as an explicit entry keyed by fileId', () => {
it('stores hidden=false as an explicit entry keyed by fileId', () => {
const store = createEditorStore()
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': true })
})
it('deletes the entry when visibility resets to hidden', () => {
const store = createEditorStore()
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': false })
})
it('deletes the entry when visibility resets to visible', () => {
const store = createEditorStore()
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
expect(store.getState().markdownFrontmatterVisible).toEqual({})
})
it('is a no-op when hiding a file that was never shown', () => {
it('is a no-op when showing a file that was never hidden', () => {
const store = createEditorStore()
const before = store.getState().markdownFrontmatterVisible
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
expect(store.getState().markdownFrontmatterVisible).toBe(before)
})
@@ -1608,7 +1608,7 @@ describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
language: 'markdown',
mode: 'edit'
})
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().closeFile('/repo/notes.md')
@@ -1630,11 +1630,11 @@ describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
worktreeId: 'wt-1',
language: 'markdown'
})
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().closeFile('/repo/notes.md')
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': true })
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': false })
store.getState().closeFile('markdown-preview::/repo/notes.md')
@@ -1662,7 +1662,7 @@ describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
},
{ sourceFileId: '/repo/notes.md' }
)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().openFile(
{
@@ -1675,7 +1675,7 @@ describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
{ preview: true }
)
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': true })
expect(store.getState().markdownFrontmatterVisible).toEqual({ '/repo/notes.md': false })
})
it('drops the visibility flag when all files are closed', () => {
@@ -1687,7 +1687,7 @@ describe('createEditorSlice markdown frontmatter visibility (#4468)', () => {
language: 'markdown',
mode: 'edit'
})
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', true)
store.getState().setMarkdownFrontmatterVisible('/repo/notes.md', false)
store.getState().closeAllFiles()
+13 -11
View File
@@ -1405,11 +1405,11 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
markdownFrontmatterVisible: {},
setMarkdownFrontmatterVisible: (fileId, visible) =>
set((s) => {
// Why: default is hidden. Writing `false` explicitly when no entry exists
// would grow the record unnecessarily; delete instead so the shape stays
// minimal and hydration round-trips cleanly — same trade-off as
// setEditorViewMode above.
if (!visible) {
// Why: default is visible. Writing `true` explicitly when no entry exists
// would grow the record unnecessarily; delete instead so the map only
// carries hide overrides and hydration round-trips cleanly — same
// trade-off as setEditorViewMode above.
if (visible) {
if (!(fileId in s.markdownFrontmatterVisible)) {
return s
}
@@ -1417,7 +1417,7 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
delete next[fileId]
return { markdownFrontmatterVisible: next }
}
return { markdownFrontmatterVisible: { ...s.markdownFrontmatterVisible, [fileId]: true } }
return { markdownFrontmatterVisible: { ...s.markdownFrontmatterVisible, [fileId]: false } }
}),
// Markdown table of contents visibility
@@ -4496,24 +4496,26 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
const nextActiveTabType =
nextActiveFileId || activeTabType !== 'editor' ? activeTabType : 'terminal'
const openFileIds = new Set(openFiles.map((file) => file.id))
const visibleFrontmatterEntries = new Map<string, boolean>()
// Why: visible is the default, so only restore per-file hide overrides
// (`false`); legacy `true` entries collapse back to the default.
const hiddenFrontmatterEntries = new Map<string, boolean>()
for (const [persistedFileId, visible] of Object.entries(
persistedMarkdownFrontmatterVisible
)) {
if (!visible) {
if (visible) {
continue
}
if (openFileIds.has(persistedFileId)) {
visibleFrontmatterEntries.set(persistedFileId, true)
hiddenFrontmatterEntries.set(persistedFileId, false)
}
for (const migrations of Object.values(editorFileIdMigrationsByWorktree)) {
const migratedFileId = migrations.get(persistedFileId)
if (migratedFileId && openFileIds.has(migratedFileId)) {
visibleFrontmatterEntries.set(migratedFileId, true)
hiddenFrontmatterEntries.set(migratedFileId, false)
}
}
}
const markdownFrontmatterVisible = Object.fromEntries(visibleFrontmatterEntries)
const markdownFrontmatterVisible = Object.fromEntries(hiddenFrontmatterEntries)
return {
openFiles,
@@ -242,7 +242,7 @@ describe('createSettingsSlice runtime switching', () => {
editorDrafts: { '/env-1/repo/stale.md': 'stale' },
markdownViewMode: { '/env-1/repo/stale.md': 'rich' },
editorViewMode: { '/env-1/repo/stale.md': 'changes' },
markdownFrontmatterVisible: { '/env-1/repo/stale.md': true },
markdownFrontmatterVisible: { '/env-1/repo/stale.md': false },
editorCursorLine: { '/env-1/repo/stale.md': 4 },
showDotfilesByWorktree: { 'repo-env-1::/env-1/repo': false },
gitIgnoredPathsByWorktree: { 'repo-env-1::/env-1/repo': ['dist/'] },
@@ -300,7 +300,7 @@ describe('createSettingsSlice runtime switching', () => {
expect(store.getState().markdownViewMode).toEqual({ '/env-1/repo/stale.md': 'rich' })
expect(store.getState().editorViewMode).toEqual({ '/env-1/repo/stale.md': 'changes' })
expect(store.getState().markdownFrontmatterVisible).toEqual({
'/env-1/repo/stale.md': true
'/env-1/repo/stale.md': false
})
expect(store.getState().editorCursorLine).toEqual({ '/env-1/repo/stale.md': 4 })
expect(store.getState().showDotfilesByWorktree).toEqual({ 'repo-env-1::/env-1/repo': false })
@@ -2079,7 +2079,7 @@ describe('hydrateEditorSession', () => {
},
activeFileIdByWorktree: { [wt]: '/path/wt1/src/index.ts' },
activeTabTypeByWorktree: { [wt]: 'editor' },
markdownFrontmatterVisible: { '/path/wt1/README.md': true }
markdownFrontmatterVisible: { '/path/wt1/README.md': false }
})
const s = store.getState()
@@ -2088,7 +2088,7 @@ describe('hydrateEditorSession', () => {
expect(s.openFiles[0].mode).toBe('edit')
expect(s.openFiles[0].isDirty).toBe(false)
expect(s.openFiles[1].isPreview).toBe(true)
expect(s.markdownFrontmatterVisible).toEqual({ '/path/wt1/README.md': true })
expect(s.markdownFrontmatterVisible).toEqual({ '/path/wt1/README.md': false })
expect(s.activeFileId).toBe('/path/wt1/src/index.ts')
expect(s.activeTabType).toBe('editor')
})
@@ -2167,10 +2167,46 @@ describe('hydrateEditorSession', () => {
[FLOATING_TERMINAL_WORKTREE_ID]: filePath
},
activeTabTypeByWorktree: { [FLOATING_TERMINAL_WORKTREE_ID]: 'editor' },
markdownFrontmatterVisible: { [filePath]: false }
})
expect(store.getState().markdownFrontmatterVisible).toEqual({ [fileId]: false })
})
it('drops legacy visible=true front-matter entries so upgraded sessions fall back to the visible default', () => {
const store = createTestStore()
const filePath = '/orca/userData/floating-workspace/note.md'
const fileId = ownedEditorFileId(filePath, FLOATING_TERMINAL_WORKTREE_ID, null)
store.setState({ activeWorktreeId: FLOATING_TERMINAL_WORKTREE_ID })
store.getState().hydrateEditorSession({
activeRepoId: null,
activeWorktreeId: FLOATING_TERMINAL_WORKTREE_ID,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
openFilesByWorktree: {
[FLOATING_TERMINAL_WORKTREE_ID]: [
{
filePath,
relativePath: 'note.md',
worktreeId: FLOATING_TERMINAL_WORKTREE_ID,
language: 'markdown',
runtimeEnvironmentId: null
}
]
},
activeFileIdByWorktree: {
[FLOATING_TERMINAL_WORKTREE_ID]: filePath
},
activeTabTypeByWorktree: { [FLOATING_TERMINAL_WORKTREE_ID]: 'editor' },
// Pre-flip sessions stored `true` for the (then non-default) visible state.
markdownFrontmatterVisible: { [filePath]: true }
})
expect(store.getState().markdownFrontmatterVisible).toEqual({ [fileId]: true })
expect(store.getState().markdownFrontmatterVisible).toEqual({})
expect(fileId in store.getState().markdownFrontmatterVisible).toBe(false)
})
it('falls back to the floating workspace file id when duplicate paths are owner-qualified', () => {