Skip to content

Commit

Permalink
feat(view:codeblock:markmap): Markmap codeblocks alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
SkepticMystic committed May 5, 2024
1 parent 60f682c commit 328441b
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/codeblocks/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ const build = (input: Record<string, unknown>, data: InputData) => {
.optional(),

type: z
.enum(["tree", "mermaid"], {
.enum(["tree", "mermaid", "markmap"], {
message: zod.error.invalid_enum(
"type",
["tree", "mermaid"],
["tree", "mermaid", "markmap"],
input["type"],
),
})
Expand Down
16 changes: 16 additions & 0 deletions src/components/Markmap/MarkmapDiagram.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts">
import type BreadcrumbsPlugin from "src/main";
import { wrap_in_codeblock } from "src/utils/strings";
import RenderMarkdown from "../obsidian/RenderMarkdown.svelte";
/** The markmap string, **not** wrapped in a codeblock */
export let markmap: string;
export let plugin: BreadcrumbsPlugin;
export let source_path: string | undefined = undefined;
</script>

<RenderMarkdown
bind:plugin
{source_path}
markdown={wrap_in_codeblock(markmap, "markmap")}
/>
114 changes: 114 additions & 0 deletions src/components/codeblocks/CodeblockMarkmap.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<script lang="ts">
import type { ICodeblock } from "src/codeblocks/schema";
import { Traverse, type EdgeTree } from "src/graph/traverse";
import {
get_edge_sorter,
has_edge_attrs,
type EdgeAttrFilters,
} from "src/graph/utils";
import type { BreadcrumbsError } from "src/interfaces/graph";
import type BreadcrumbsPlugin from "src/main";
import { active_file_store } from "src/stores/active_file";
import { Markmap } from "src/utils/markmap";
import { onMount } from "svelte";
import MarkmapDiagram from "../Markmap/MarkmapDiagram.svelte";
import CopyToClipboardButton from "../button/CopyToClipboardButton.svelte";
import CodeblockErrors from "./CodeblockErrors.svelte";
export let plugin: BreadcrumbsPlugin;
export let options: ICodeblock["Options"];
export let errors: BreadcrumbsError[];
export let file_path: string;
const sort = get_edge_sorter(
// @ts-expect-error: ts(2345)
options.sort,
plugin.graph,
);
const { show_node_options } = plugin.settings.views.codeblocks;
let tree: EdgeTree[] = [];
// if the file_path is an empty string, so the code block is not rendered inside note, we fall back to the active file store
$: source_path = file_path
? file_path
: $active_file_store
? $active_file_store.path
: "";
// this is an exposed function that we can call from the outside to update the codeblock
export const update = () => {
tree = Traverse.sort_edge_tree(get_tree(), sort);
};
const base_traversal = (attr: EdgeAttrFilters) =>
Traverse.build_tree(
plugin.graph,
source_path,
{ max_depth: options.depth[1] },
(e) =>
has_edge_attrs(e, {
...attr,
$or_target_ids: options["dataview-from-paths"],
}),
);
const edge_field_labels =
options.fields ?? plugin.settings.edge_fields.map((f) => f.label);
const get_tree = () => {
if (source_path && plugin.graph.hasNode(source_path)) {
const traversal = options["merge-fields"]
? base_traversal({ $or_fields: options.fields })
: edge_field_labels.flatMap((field) =>
base_traversal({ field }),
);
// NOTE: The flattening is done here so that:
// - We can use NestedEdgeList for both modes
// - ListIndex builds from an EdgeTree[] as well
return options.flat
? Traverse.flatten_tree(traversal).map((item) => ({
depth: 0,
children: [],
edge: item.edge,
}))
: traversal;
} else {
return [];
}
};
$: markmap = Markmap.from_tree(tree, {
show_node_options,
show_attributes: options?.["show-attributes"],
});
onMount(update);
</script>

<div class="BC-codeblock-markmap">
<CodeblockErrors {plugin} {errors} />

{#if options.title}
<h3 class="BC-codeblock-markmap-title">
{options.title}
</h3>
{/if}

{#if tree.length}
<div class="relative">
<div class="absolute left-2 top-2 flex">
<CopyToClipboardButton
text={markmap}
cls="clickable-icon nav-action-button"
/>
</div>

<MarkmapDiagram {plugin} {markmap} {source_path} />
</div>
{:else}
<!-- TODO(HELP-MSG) -->
<p class="search-empty-state">No paths found.</p>
{/if}
</div>
42 changes: 42 additions & 0 deletions src/utils/markmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { EdgeAttribute } from "src/graph/MyMultiGraph";
import type { EdgeTree } from "src/graph/traverse";
import type { ShowNodeOptions } from "src/interfaces/settings";
import { Links } from "./links";
import { untyped_pick } from "./objects";
import { Paths } from "./paths";
import { url_search_params } from "./url";

type Options = {
show_attributes?: EdgeAttribute[];
show_node_options?: ShowNodeOptions;
};

const from_tree = (tree: EdgeTree[], options?: Options) => {
let markmap = "";

tree.forEach((item) => {
const hashes = "#".repeat(item.depth);

const link = Links.ify(
item.edge.target_id,
Paths.show(item.edge.target_id, options?.show_node_options),
{ link_kind: "markdown" },
);

const attr = options?.show_attributes
? ` (${url_search_params(untyped_pick(item.edge.attr, options.show_attributes), { trim_lone_param: true })})`
: "";

markmap += `${hashes} ${link}${attr}\n`;

if (item.children.length) {
markmap += from_tree(item.children, options);
}
});

return markmap;
};

export const Markmap = {
from_tree,
};

0 comments on commit 328441b

Please sign in to comment.