@riebeckite/plugin-excalibrain 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +165 -0
- package/README_ja.md +150 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +100 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +785 -0
- package/dist/src/graph.d.ts +7 -0
- package/dist/src/init.d.ts +6 -0
- package/dist/src/layout.d.ts +9 -0
- package/dist/src/ontology.d.ts +36 -0
- package/dist/src/options.d.ts +20 -0
- package/dist/src/placeholder.d.ts +5 -0
- package/dist/src/rehype.d.ts +9 -0
- package/dist/src/render.d.ts +11 -0
- package/dist/src/types.d.ts +123 -0
- package/package.json +61 -0
- package/style.css +94 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExcaliBrainBuildInput, ExcaliBrainGraph } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build the ExcaliBrain graph for a single note. Explicit (ontology) relations
|
|
4
|
+
* always win over inferred ones; link inference derives parents from backlinks,
|
|
5
|
+
* children from outgoing links, and left friends from mutual links.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildExcaliBrainGraph(input: ExcaliBrainBuildInput): ExcaliBrainGraph;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ExcaliBrainClientOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Build the SVG for every client-rendered ExcaliBrain canvas. Canvases that
|
|
4
|
+
* already contain a build-time SVG (the `both` mode) are left untouched.
|
|
5
|
+
*/
|
|
6
|
+
export declare function initExcaliBrain(options?: ExcaliBrainClientOptions): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ExcaliBrainGraph, ExcaliBrainLayout, ExcaliBrainOptions, ExcaliBrainRegion } from "./types.js";
|
|
2
|
+
export declare const EXCALIBRAIN_REGION_ORDER: readonly ExcaliBrainRegion[];
|
|
3
|
+
/**
|
|
4
|
+
* Position every node in its ExcaliBrain region. Parents sit at the top,
|
|
5
|
+
* children at the bottom, friends at the sides, previous/next at the far
|
|
6
|
+
* left/right, and siblings around the periphery. Ordering within a region is
|
|
7
|
+
* by title, so the layout is fully deterministic.
|
|
8
|
+
*/
|
|
9
|
+
export declare function layoutExcaliBrain(graph: ExcaliBrainGraph, options?: ExcaliBrainOptions): ExcaliBrainLayout;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ExcaliBrainOntology, ExcaliBrainNodeRole } from "./types.js";
|
|
2
|
+
export type ExcaliBrainFieldRole = "parents" | "children" | "leftFriends" | "rightFriends" | "previous" | "next" | "hidden";
|
|
3
|
+
/** ExcaliBrain's default ontology field names. */
|
|
4
|
+
export declare const DEFAULT_ONTOLOGY: Required<ExcaliBrainOntology>;
|
|
5
|
+
/** Canonical processing order; earlier roles win when a target is listed twice. */
|
|
6
|
+
export declare const FIELD_ROLE_ORDER: readonly ExcaliBrainFieldRole[];
|
|
7
|
+
export type ResolvedOntology = {
|
|
8
|
+
/** Normalized field name to ontology role. */
|
|
9
|
+
fieldRole: Map<string, ExcaliBrainFieldRole>;
|
|
10
|
+
};
|
|
11
|
+
export type DefinedRelation = {
|
|
12
|
+
role: ExcaliBrainNodeRole;
|
|
13
|
+
target: string;
|
|
14
|
+
};
|
|
15
|
+
/** Lowercase a field name and normalize spaces to hyphens. */
|
|
16
|
+
export declare function normalizeFieldName(value: string): string;
|
|
17
|
+
export declare function resolveOntology(overrides?: ExcaliBrainOntology): ResolvedOntology;
|
|
18
|
+
export declare function fieldRoleOf(field: string, ontology: ResolvedOntology): ExcaliBrainFieldRole | null;
|
|
19
|
+
/**
|
|
20
|
+
* Collect explicit relations from YAML frontmatter and dataview inline fields.
|
|
21
|
+
* Results follow {@link FIELD_ROLE_ORDER} so defined relations are deterministic.
|
|
22
|
+
*/
|
|
23
|
+
export declare function collectDefinedRelations(input: {
|
|
24
|
+
frontmatter: Record<string, unknown>;
|
|
25
|
+
markdown: string;
|
|
26
|
+
ontology: ResolvedOntology;
|
|
27
|
+
}): DefinedRelation[];
|
|
28
|
+
export declare function isNoteHidden(input: {
|
|
29
|
+
frontmatter: Record<string, unknown>;
|
|
30
|
+
markdown: string;
|
|
31
|
+
ontology: ResolvedOntology;
|
|
32
|
+
}): boolean;
|
|
33
|
+
/** Extract `[[target]]` link targets from a raw value. */
|
|
34
|
+
export declare function extractWikilinkTargets(value: string): string[];
|
|
35
|
+
/** Extract `Field:: value` pairs from the note body (frontmatter excluded). */
|
|
36
|
+
export declare function extractInlineFields(markdown: string): Array<[string, string]>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ConfigValidationIssue } from "@riebeckite/core";
|
|
2
|
+
import { type ResolvedOntology } from "./ontology.js";
|
|
3
|
+
import type { ExcaliBrainOptions, ExcaliBrainRenderMode } from "./types.js";
|
|
4
|
+
export type ResolvedExcaliBrainOptions = {
|
|
5
|
+
render: ExcaliBrainRenderMode;
|
|
6
|
+
auto: boolean;
|
|
7
|
+
heading: boolean;
|
|
8
|
+
headingText: string;
|
|
9
|
+
className: string;
|
|
10
|
+
maxPerRegion: number;
|
|
11
|
+
infer: boolean;
|
|
12
|
+
siblings: boolean;
|
|
13
|
+
ontology: ResolvedOntology;
|
|
14
|
+
showHidden: boolean;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
language: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function resolveExcaliBrainOptions(options?: ExcaliBrainOptions): ResolvedExcaliBrainOptions;
|
|
20
|
+
export declare function validateExcaliBrainOptions(options: ExcaliBrainOptions | undefined): readonly ConfigValidationIssue[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const EXCALIBRAIN_PLACEHOLDER_ATTRIBUTE = "data-rb-excalibrain";
|
|
2
|
+
export declare function createExcaliBrainPlaceholder(): string;
|
|
3
|
+
export declare function createExcaliBrainPlaceholderPattern(): RegExp;
|
|
4
|
+
export declare function hasExcaliBrainPlaceholder(html: string): boolean;
|
|
5
|
+
export declare function replaceExcaliBrainPlaceholders(html: string, replacement: string): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HastNode } from "./types.js";
|
|
2
|
+
export type RehypeExcaliBrainOptions = {
|
|
3
|
+
language?: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Replace every ` ```excalibrain ` code block with a placeholder div that is
|
|
7
|
+
* resolved against the content manifest in `onManifestCreated`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function rehypeExcaliBrain(options?: RehypeExcaliBrainOptions): (tree: HastNode) => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ExcaliBrainGraph, ExcaliBrainLayout, ExcaliBrainOptions, ExcaliBrainRenderMode } from "./types.js";
|
|
2
|
+
export type ExcaliBrainSectionInput = {
|
|
3
|
+
graph: ExcaliBrainGraph;
|
|
4
|
+
layout: ExcaliBrainLayout;
|
|
5
|
+
options?: ExcaliBrainOptions;
|
|
6
|
+
render?: ExcaliBrainRenderMode;
|
|
7
|
+
};
|
|
8
|
+
/** Render the map as a standalone SVG string. Shared by build and client. */
|
|
9
|
+
export declare function renderExcaliBrainSvg(graph: ExcaliBrainGraph, layout: ExcaliBrainLayout, options?: ExcaliBrainOptions): string;
|
|
10
|
+
/** Render the `<section>` wrapper, with inline SVG and/or a client canvas. */
|
|
11
|
+
export declare function renderExcaliBrainSection(input: ExcaliBrainSectionInput): string;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ContentManifest } from "@riebeckite/core";
|
|
2
|
+
export type ExcaliBrainRenderMode = "build" | "client" | "both";
|
|
3
|
+
/**
|
|
4
|
+
* ExcaliBrain relationship roles. Mirrors Zsolt Viczián's ExcaliBrain:
|
|
5
|
+
* parents, children, left/right friends, previous/next, and siblings.
|
|
6
|
+
*/
|
|
7
|
+
export type ExcaliBrainRole = "parent" | "child" | "leftFriend" | "rightFriend" | "previous" | "next" | "sibling";
|
|
8
|
+
export type ExcaliBrainNodeRole = ExcaliBrainRole | "center";
|
|
9
|
+
export type ExcaliBrainRelationType = "defined" | "inferred";
|
|
10
|
+
/** Ontology field overrides. Field names are matched case-insensitively. */
|
|
11
|
+
export type ExcaliBrainOntology = {
|
|
12
|
+
parents?: readonly string[];
|
|
13
|
+
children?: readonly string[];
|
|
14
|
+
leftFriends?: readonly string[];
|
|
15
|
+
rightFriends?: readonly string[];
|
|
16
|
+
previous?: readonly string[];
|
|
17
|
+
next?: readonly string[];
|
|
18
|
+
hidden?: readonly string[];
|
|
19
|
+
};
|
|
20
|
+
export type ExcaliBrainOptions = {
|
|
21
|
+
/** Where the map is rendered: build-time SVG, client-side, or both. */
|
|
22
|
+
render?: ExcaliBrainRenderMode;
|
|
23
|
+
/** Append the map to notes without an explicit fence. */
|
|
24
|
+
auto?: boolean;
|
|
25
|
+
/** Show the optional heading. */
|
|
26
|
+
heading?: boolean;
|
|
27
|
+
/** Heading text. */
|
|
28
|
+
headingText?: string;
|
|
29
|
+
/** Root CSS class. */
|
|
30
|
+
className?: string;
|
|
31
|
+
/** Maximum nodes rendered per region. */
|
|
32
|
+
maxPerRegion?: number;
|
|
33
|
+
/** Infer relationships from links when no explicit relation exists. */
|
|
34
|
+
infer?: boolean;
|
|
35
|
+
/** Infer siblings from the children of this note's parents. */
|
|
36
|
+
siblings?: boolean;
|
|
37
|
+
/** Ontology field overrides. */
|
|
38
|
+
ontology?: ExcaliBrainOntology;
|
|
39
|
+
/** Include notes marked hidden by the ontology. */
|
|
40
|
+
showHidden?: boolean;
|
|
41
|
+
/** SVG viewBox width. */
|
|
42
|
+
width?: number;
|
|
43
|
+
/** SVG viewBox height. */
|
|
44
|
+
height?: number;
|
|
45
|
+
/** Fence language that produces a map. */
|
|
46
|
+
language?: string;
|
|
47
|
+
};
|
|
48
|
+
export type ExcaliBrainNode = {
|
|
49
|
+
id: string;
|
|
50
|
+
slug: string | null;
|
|
51
|
+
title: string;
|
|
52
|
+
permalink: string | null;
|
|
53
|
+
virtual: boolean;
|
|
54
|
+
role: ExcaliBrainNodeRole;
|
|
55
|
+
relationType: ExcaliBrainRelationType;
|
|
56
|
+
};
|
|
57
|
+
export type ExcaliBrainLink = {
|
|
58
|
+
from: string;
|
|
59
|
+
to: string;
|
|
60
|
+
role: ExcaliBrainRole;
|
|
61
|
+
relationType: ExcaliBrainRelationType;
|
|
62
|
+
};
|
|
63
|
+
export type ExcaliBrainGraph = {
|
|
64
|
+
center: ExcaliBrainNode;
|
|
65
|
+
nodes: ExcaliBrainNode[];
|
|
66
|
+
links: ExcaliBrainLink[];
|
|
67
|
+
};
|
|
68
|
+
export type ExcaliBrainBuildInput = {
|
|
69
|
+
slug: string;
|
|
70
|
+
frontmatter: Record<string, unknown>;
|
|
71
|
+
markdown: string;
|
|
72
|
+
manifest: ContentManifest;
|
|
73
|
+
options?: ExcaliBrainOptions;
|
|
74
|
+
};
|
|
75
|
+
export type ExcaliBrainRegion = "parents" | "children" | "left-friends" | "right-friends" | "previous" | "next" | "siblings" | "center";
|
|
76
|
+
export type ExcaliBrainPositionedNode = {
|
|
77
|
+
id: string;
|
|
78
|
+
role: ExcaliBrainNodeRole;
|
|
79
|
+
region: ExcaliBrainRegion;
|
|
80
|
+
relationType: ExcaliBrainRelationType;
|
|
81
|
+
title: string;
|
|
82
|
+
slug: string | null;
|
|
83
|
+
permalink: string | null;
|
|
84
|
+
virtual: boolean;
|
|
85
|
+
/** Top-left corner of the node box. */
|
|
86
|
+
x: number;
|
|
87
|
+
y: number;
|
|
88
|
+
width: number;
|
|
89
|
+
height: number;
|
|
90
|
+
};
|
|
91
|
+
export type ExcaliBrainPositionedLink = {
|
|
92
|
+
from: string;
|
|
93
|
+
to: string;
|
|
94
|
+
role: ExcaliBrainRole;
|
|
95
|
+
relationType: ExcaliBrainRelationType;
|
|
96
|
+
};
|
|
97
|
+
export type ExcaliBrainLayout = {
|
|
98
|
+
width: number;
|
|
99
|
+
height: number;
|
|
100
|
+
nodes: ExcaliBrainPositionedNode[];
|
|
101
|
+
links: ExcaliBrainPositionedLink[];
|
|
102
|
+
};
|
|
103
|
+
export type ExcaliBrainClientOptions = {
|
|
104
|
+
className?: string;
|
|
105
|
+
};
|
|
106
|
+
export type ElementNode = {
|
|
107
|
+
type: string;
|
|
108
|
+
tagName?: string;
|
|
109
|
+
properties?: Record<string, unknown>;
|
|
110
|
+
children?: HastNode[];
|
|
111
|
+
};
|
|
112
|
+
export type TextNode = {
|
|
113
|
+
type: "text";
|
|
114
|
+
value: string;
|
|
115
|
+
};
|
|
116
|
+
export type RawNode = {
|
|
117
|
+
type: "raw";
|
|
118
|
+
value: string;
|
|
119
|
+
};
|
|
120
|
+
export type HastNode = ElementNode | TextNode | RawNode | {
|
|
121
|
+
type: string;
|
|
122
|
+
[key: string]: unknown;
|
|
123
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@riebeckite/plugin-excalibrain",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"source": "./index.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./client": {
|
|
16
|
+
"types": "./dist/client.d.ts",
|
|
17
|
+
"import": "./dist/client.js",
|
|
18
|
+
"source": "./client.ts",
|
|
19
|
+
"default": "./dist/client.js"
|
|
20
|
+
},
|
|
21
|
+
"./style.css": "./style.css"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@riebeckite/core": "0.0.1"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"README.md",
|
|
32
|
+
"README_ja.md",
|
|
33
|
+
"dist",
|
|
34
|
+
"style.css"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/Rerurate514/riebeckite.git",
|
|
39
|
+
"directory": "packages/plugins/excalibrain"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/Rerurate514/riebeckite#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/Rerurate514/riebeckite/issues"
|
|
44
|
+
},
|
|
45
|
+
"description": "Relationship maps for Riebeckite notes inspired by ExcaliBrain.",
|
|
46
|
+
"keywords": [
|
|
47
|
+
"riebeckite",
|
|
48
|
+
"plugin",
|
|
49
|
+
"graph",
|
|
50
|
+
"obsidian"
|
|
51
|
+
],
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
54
|
+
},
|
|
55
|
+
"sideEffects": [
|
|
56
|
+
"./style.css"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "node ../../../scripts/build_package.mjs"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/style.css
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
.rb-excalibrain {
|
|
2
|
+
--rb-excalibrain-ink: var(--rb-color-ink, #000000);
|
|
3
|
+
--rb-excalibrain-paper: var(--rb-color-paper, #ffffff);
|
|
4
|
+
--rb-excalibrain-muted: var(--rb-color-muted, #69645c);
|
|
5
|
+
--rb-excalibrain-accent: var(--rb-color-accent, #686868);
|
|
6
|
+
--rb-excalibrain-rule: var(
|
|
7
|
+
--rb-color-border,
|
|
8
|
+
color-mix(in srgb, var(--rb-excalibrain-ink) 18%, transparent)
|
|
9
|
+
);
|
|
10
|
+
--rb-excalibrain-surface: color-mix(
|
|
11
|
+
in srgb,
|
|
12
|
+
var(--rb-excalibrain-paper) 95%,
|
|
13
|
+
var(--rb-excalibrain-ink)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
margin: 2rem 0;
|
|
17
|
+
color: var(--rb-excalibrain-ink);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.rb-excalibrain__heading {
|
|
21
|
+
margin: 0 0 0.5rem;
|
|
22
|
+
font-size: 1rem;
|
|
23
|
+
font-weight: 700;
|
|
24
|
+
letter-spacing: 0.02em;
|
|
25
|
+
text-transform: uppercase;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.rb-excalibrain__canvas {
|
|
29
|
+
overflow: auto;
|
|
30
|
+
border: 1px solid var(--rb-excalibrain-rule);
|
|
31
|
+
background: var(--rb-excalibrain-surface);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.rb-excalibrain__svg {
|
|
35
|
+
display: block;
|
|
36
|
+
width: 100%;
|
|
37
|
+
min-width: 32rem;
|
|
38
|
+
height: auto;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.rb-excalibrain__link {
|
|
42
|
+
fill: none;
|
|
43
|
+
stroke: var(--rb-excalibrain-rule);
|
|
44
|
+
stroke-width: 1.25;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.rb-excalibrain__link[data-relation-type="defined"] {
|
|
48
|
+
stroke: var(--rb-excalibrain-accent);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.rb-excalibrain__node-box {
|
|
52
|
+
fill: var(--rb-excalibrain-paper);
|
|
53
|
+
stroke: var(--rb-excalibrain-rule);
|
|
54
|
+
stroke-width: 1.25;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.rb-excalibrain__node[data-node-role="center"] .rb-excalibrain__node-box {
|
|
58
|
+
stroke: var(--rb-excalibrain-ink);
|
|
59
|
+
stroke-width: 2;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.rb-excalibrain__node[data-node-virtual="true"] .rb-excalibrain__node-box {
|
|
63
|
+
fill: none;
|
|
64
|
+
stroke-dasharray: 4 3;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.rb-excalibrain__node-label {
|
|
68
|
+
fill: var(--rb-excalibrain-ink);
|
|
69
|
+
font-size: 0.8125rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.rb-excalibrain__node-link {
|
|
73
|
+
text-decoration: none;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.rb-excalibrain__node-link:hover .rb-excalibrain__node-box,
|
|
77
|
+
.rb-excalibrain__node-link:focus-visible .rb-excalibrain__node-box {
|
|
78
|
+
stroke: var(--rb-excalibrain-accent);
|
|
79
|
+
stroke-width: 2;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.rb-excalibrain[data-excalibrain-render="client"] .rb-excalibrain__canvas:empty::before {
|
|
83
|
+
display: block;
|
|
84
|
+
padding: 1rem;
|
|
85
|
+
content: "ExcaliBrain map is rendered in the browser.";
|
|
86
|
+
color: var(--rb-excalibrain-muted);
|
|
87
|
+
font-size: 0.8125rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
html[data-theme="dark"] .rb-excalibrain,
|
|
91
|
+
html.dark .rb-excalibrain {
|
|
92
|
+
--rb-excalibrain-ink: var(--rb-color-paper, #ffffff);
|
|
93
|
+
--rb-excalibrain-paper: var(--rb-color-ink, #000000);
|
|
94
|
+
}
|