feat(workspace): journal panel toggle, view kept across tabs, sections nest under headings
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m9s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m9s
- the journal opens as a framed panel and closes on a second click, returning to the previous note; journal state and the last regular note survive tab switches, the fallback note is never a journal day - pasted and imported markdown nests content under its heading (H2 below H1), Enter on a heading creates a child, '- ' / '* ' / '+ ' start a bullet Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc7bdc481e
commit
375dda982b
9 files changed
+145
-36
No files matched your search
@@ -2,6 +2,7 @@ import type { BlockType } from './types';
|
||||
|
||||
// Turns pasted (Markdown) text into outline items: headings, todos, bullets, numbered items, dividers,
|
||||
// fenced code and paragraphs. A blank line ends a paragraph; indentation becomes the nesting level.
|
||||
// Content below a heading is nested under it (H2 below H1 one level deeper), so sections fold and zoom.
|
||||
|
||||
export interface PastedItem {
|
||||
type: BlockType;
|
||||
@@ -31,6 +32,8 @@ export function parsePastedLines(rawLines: string[]): PastedItem[] {
|
||||
let current: PastedItem | null = null;
|
||||
let inCode = false;
|
||||
let afterHeading = false;
|
||||
const headings: { rank: number; level: number }[] = []; // open headings, innermost last
|
||||
const sectionLevel = () => (headings.length ? headings[headings.length - 1].level + 1 : 0);
|
||||
|
||||
const flush = () => {
|
||||
if (current) {
|
||||
@@ -52,13 +55,13 @@ export function parsePastedLines(rawLines: string[]): PastedItem[] {
|
||||
if (rawLine.trim().startsWith('```')) {
|
||||
inCode = true;
|
||||
flush();
|
||||
current = { type: 'text', content: rawLine, indent: 0 };
|
||||
current = { type: 'text', content: rawLine, indent: sectionLevel() };
|
||||
afterHeading = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const { width, rest } = leadingWidth(rawLine);
|
||||
const indent = levelOf(width);
|
||||
const indent = sectionLevel() + levelOf(width);
|
||||
const line = rest.trimEnd();
|
||||
|
||||
// A blank line ends the paragraph or list item
|
||||
@@ -71,13 +74,18 @@ export function parsePastedLines(rawLines: string[]): PastedItem[] {
|
||||
if (heading) {
|
||||
flush();
|
||||
afterHeading = true;
|
||||
items.push({ type: (['h1', 'h2', 'h3'] as const)[heading[1].length - 1], content: heading[2], indent });
|
||||
const rank = heading[1].length;
|
||||
while (headings.length && headings[headings.length - 1].rank >= rank) headings.pop();
|
||||
const level = sectionLevel();
|
||||
headings.push({ rank, level });
|
||||
items.push({ type: (['h1', 'h2', 'h3'] as const)[rank - 1], content: heading[2], indent: level });
|
||||
continue;
|
||||
}
|
||||
if (/^(?:-{3,}|\*{3,}|_{3,})$/.test(line)) {
|
||||
flush();
|
||||
afterHeading = false;
|
||||
items.push({ type: 'divider', content: '---', indent });
|
||||
headings.length = 0; // a divider closes the sections
|
||||
items.push({ type: 'divider', content: '---', indent: 0 });
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user