Skip to content

Commit 8c69405

Browse files
committed
enhance: preview content before splitting
1 parent e3301d1 commit 8c69405

17 files changed

Lines changed: 447 additions & 61 deletions

File tree

package-lock.json

Lines changed: 23 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"tiny-invariant": "1.3.3",
5151
"tslib": "2.6.2",
5252
"typescript": "5.3.3",
53-
"vitest": "1.3.1"
53+
"vitest": "1.3.1",
54+
"@types/diff": "^5.2.1",
55+
"diff": "^5.2.0"
5456
}
5557
}

src/lib/data-conversion/headings-to-json.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const headingsToJson = (input: string): TreeNode[] => {
1111
const lines = input.split('\n');
1212
const highestHeadingLevel = findHighestHeadingLevel(lines);
1313
const state: State = {
14-
currentNodes: [],
14+
currentParents: {},
1515
currentNode: null,
1616
tree: [],
1717
};

src/lib/data-conversion/headings-to-sections.spec.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,4 +868,75 @@ describe('headingsToSections', () => {
868868
## H2`;
869869
expect(headingsToSections(input)).toEqual(output);
870870
});
871+
872+
test('first level is not h1 (3)', () => {
873+
const input = `## H2
874+
875+
text 1
876+
#### H4
877+
878+
879+
text 2
880+
### H3
881+
882+
text 3`;
883+
884+
const output = `
885+
<!--section: 1-->
886+
## H2
887+
888+
text 1
889+
890+
<!--section: 1.1-->
891+
### H4
892+
893+
894+
text 2
895+
896+
<!--section: 1.2-->
897+
### H3
898+
899+
text 3`;
900+
expect(headingsToSections(input)).toEqual(output);
901+
});
902+
903+
test('weird bug', () => {
904+
const input = `## H2
905+
906+
### H3
907+
908+
text 1
909+
910+
### H3
911+
912+
text 2
913+
#### H4
914+
915+
- item 1.
916+
- item 2
917+
- item 3`;
918+
const output = `
919+
<!--section: 1-->
920+
## H2
921+
922+
923+
<!--section: 1.1-->
924+
### H3
925+
926+
text 1
927+
928+
929+
<!--section: 1.2-->
930+
### H3
931+
932+
text 2
933+
934+
<!--section: 1.2.1-->
935+
#### H4
936+
937+
- item 1.
938+
- item 2
939+
- item 3`;
940+
expect(headingsToSections(input)).toEqual(output);
941+
});
871942
});

src/lib/data-conversion/outilne-to-json.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { parseDelimiter } from 'src/lib/data-conversion/helpers/delimiter';
22
import { TreeNode } from 'src/lib/data-conversion/columns-to-json';
33

44
export type State = {
5-
currentNodes: TreeNode[];
5+
currentParents: Record<string, TreeNode>;
66
currentNode: null | TreeNode;
77
tree: TreeNode[];
88
};
@@ -17,17 +17,24 @@ export const addNewNode = (
1717
content: text,
1818
children: [],
1919
};
20+
21+
// remove parents that have a higher level (e.g, when going from H4 to H2, H3-H6 are deleted)
22+
for (const key of Object.keys(state.currentParents)) {
23+
const parentLevel = +key;
24+
if (parentLevel >= level) {
25+
delete state.currentParents[key];
26+
}
27+
}
28+
2029
if (level === root) {
2130
state.tree.push(state.currentNode);
22-
state.currentNodes = [state.currentNode];
23-
} else {
24-
if (state.currentNodes[level - (1 + root)]) {
25-
state.currentNodes[level - (1 + root)].children.push(
26-
state.currentNode,
27-
);
28-
}
29-
state.currentNodes[level - 1] = state.currentNode;
3031
}
32+
state.currentParents[level] = state.currentNode;
33+
const parent = state.currentParents[level - 1];
34+
if (parent) {
35+
parent.children.push(state.currentNode);
36+
} else if (level > root)
37+
throw new Error(`Item [${text}] does not have a parent`);
3138
};
3239

3340
export const updateCurrentNode = (state: State, text: string) => {
@@ -46,7 +53,7 @@ export const updateCurrentNode = (state: State, text: string) => {
4653
export const outlineToJson = (input: string): TreeNode[] => {
4754
const lines = input.split('\n');
4855
const state: State = {
49-
currentNodes: [],
56+
currentParents: {},
5057
currentNode: null,
5158
tree: [],
5259
};

src/stores/document/reducers/split-node/split-node.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('split node', () => {
2626
};
2727
const action = {
2828
type: 'DOCUMENT/SPLIT_NODE',
29-
payload: { target: 'nP3BBw00m', mode: 'heading' },
29+
payload: { target: 'nP3BBw00m', mode: 'headings' },
3030
} as const;
3131
const output = {
3232
columns: [
@@ -229,7 +229,7 @@ describe('split node', () => {
229229
const inputClone = clone(input);
230230
const action = {
231231
type: 'DOCUMENT/SPLIT_NODE',
232-
payload: { target: 'nO5aXT_Tq', mode: 'heading' },
232+
payload: { target: 'nO5aXT_Tq', mode: 'headings' },
233233
} as const;
234234

235235
expect(() => splitNode(input, action)).toThrow(
@@ -268,7 +268,7 @@ describe('split node', () => {
268268
};
269269
const action = {
270270
type: 'DOCUMENT/SPLIT_NODE',
271-
payload: { target: 'nO5aXT_Tq', mode: 'heading' },
271+
payload: { target: 'nO5aXT_Tq', mode: 'headings' },
272272
} as const;
273273
const output = {
274274
columns: [
@@ -322,7 +322,7 @@ describe('split node', () => {
322322
const inputClone = clone(input);
323323
const action = {
324324
type: 'DOCUMENT/SPLIT_NODE',
325-
payload: { target: 'nVPwysBOU', mode: 'heading' },
325+
payload: { target: 'nVPwysBOU', mode: 'headings' },
326326
} as const;
327327

328328
expect(() => splitNode(input, action)).toThrow(
@@ -347,7 +347,7 @@ describe('split node', () => {
347347
const inputClone = clone(input);
348348
const action = {
349349
type: 'DOCUMENT/SPLIT_NODE',
350-
payload: { target: 'nVPwysBOU', mode: 'heading' },
350+
payload: { target: 'nVPwysBOU', mode: 'headings' },
351351
} as const;
352352

353353
expect(() => splitNode(input, action)).toThrow('input has a section');

src/stores/document/reducers/split-node/split-node.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { lang } from 'src/lang/lang';
77
import { headingsToSections } from 'src/lib/data-conversion/headings-to-sections';
88
import { outlineToSections } from 'src/lib/data-conversion/outline-to-sections';
99

10-
export type SplitNodeMode = 'heading' | 'outline';
10+
export type SplitNodeMode = 'headings' | 'outline';
1111
export type SplitNodeAction = {
1212
type: 'DOCUMENT/SPLIT_NODE';
1313
payload: {
@@ -16,17 +16,20 @@ export type SplitNodeAction = {
1616
};
1717
};
1818

19+
export const splitText = (text: string, mode: SplitNodeMode) => {
20+
return mode === 'headings'
21+
? headingsToSections(text)
22+
: outlineToSections(text);
23+
};
24+
1925
export const splitNode = (
2026
document: LineageDocument,
2127
action: Pick<SplitNodeAction, 'payload'>,
2228
) => {
2329
const targetNode = action.payload.target;
2430
const content = document.content[targetNode];
2531
if (!content?.content) throw new SilentError('empty node');
26-
const sections =
27-
action.payload.mode === 'heading'
28-
? headingsToSections(content.content)
29-
: outlineToSections(content.content);
32+
const sections = splitText(content?.content, action.payload.mode);
3033
if (sections === content.content)
3134
throw new Error(lang.cant_split_card_identical);
3235
const childGroup = findChildGroup(document.columns, targetNode);

src/view/actions/context-menu/card-context-menu/show-card-context-menu.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ import { mergeNode } from 'src/view/actions/keyboard-shortcuts/helpers/commands/
55
import { copyNode } from 'src/view/actions/keyboard-shortcuts/helpers/commands/commands/helpers/copy-node';
66
import { cutNode } from 'src/view/actions/keyboard-shortcuts/helpers/commands/commands/helpers/cut-node';
77
import { pasteNode } from 'src/view/actions/keyboard-shortcuts/helpers/commands/commands/helpers/paste-node';
8-
import { splitNode } from 'src/view/actions/keyboard-shortcuts/helpers/commands/commands/helpers/split-node';
8+
import { openSplitNodeModal } from 'src/view/modals/split-node-modal/open-split-node-modal';
99
import { customIcons } from 'src/helpers/load-custom-icons';
10-
import { hasNHeadings } from 'src/lib/format-detection/has-n-headings';
11-
import { isOutline } from 'src/lib/format-detection/is-outline';
1210
import { copyLinkToBlock } from 'src/view/actions/context-menu/card-context-menu/helpers/copy-link-to-block';
1311

1412
export const showCardContextMenu = (event: MouseEvent, view: LineageView) => {
@@ -27,32 +25,15 @@ export const showCardContextMenu = (event: MouseEvent, view: LineageView) => {
2725
.setDisabled(multipleNodesAreSelected),
2826
);
2927

30-
const input =
31-
view.documentStore.getValue().document.content[
32-
view.viewStore.getValue().document.activeNode
33-
]?.content || '';
34-
3528
menu.addSeparator();
3629

37-
const _hasHeading = hasNHeadings(input);
38-
const _isOutline = !_hasHeading && isOutline(input);
3930
menu.addItem((item) =>
4031
item
41-
.setTitle('Split by headings')
32+
.setTitle('Split')
4233
.setIcon(customIcons.split.name)
4334
.onClick(() => {
44-
splitNode(view, 'heading');
45-
})
46-
.setDisabled(!_hasHeading || multipleNodesAreSelected),
47-
);
48-
menu.addItem((item) =>
49-
item
50-
.setTitle('Split outline')
51-
.setIcon(customIcons.split.name)
52-
.onClick(() => {
53-
splitNode(view, 'outline');
54-
})
55-
.setDisabled(!_isOutline || multipleNodesAreSelected),
35+
openSplitNodeModal(view);
36+
}),
5637
);
5738

5839
menu.addSeparator();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
/* eslint-disable svelte/no-at-html-tags */
3+
import { getModalState } from 'src/view/modals/split-node-modal/helpers/get-modal-state';
4+
5+
const state = getModalState();
6+
7+
const mode = state.mode;
8+
const content = state.content;
9+
</script>
10+
11+
<div>
12+
{#if !$mode}
13+
<p class="mod-warning">
14+
This card's content does not match any splitting pattern
15+
</p>
16+
{/if}
17+
</div>
18+
<div class="preview">
19+
{@html $content}
20+
</div>
21+
22+
<style>
23+
.preview {
24+
flex-grow: 1;
25+
max-height: 500px;
26+
overflow: auto;
27+
}
28+
</style>

0 commit comments

Comments
 (0)