@openparachute/vault 0.2.4 → 0.3.0-rc.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/.claude/settings.local.json +2 -25
- package/CHANGELOG.md +64 -0
- package/CLAUDE.md +17 -7
- package/README.md +169 -136
- package/core/src/core.test.ts +591 -19
- package/core/src/indexed-fields.test.ts +285 -0
- package/core/src/indexed-fields.ts +238 -0
- package/core/src/mcp.ts +127 -6
- package/core/src/notes.ts +153 -11
- package/core/src/query-operators.ts +174 -0
- package/core/src/schema.ts +69 -2
- package/core/src/store.ts +92 -0
- package/core/src/tag-schemas.ts +5 -0
- package/core/src/types.ts +28 -1
- package/docs/HTTP_API.md +105 -1
- package/package/package.json +32 -0
- package/package.json +2 -2
- package/src/auth.test.ts +83 -114
- package/src/auth.ts +68 -6
- package/src/backup-launchd.ts +1 -1
- package/src/backup.test.ts +1 -1
- package/src/backup.ts +18 -17
- package/src/cli.ts +179 -121
- package/src/config-triggers.test.ts +49 -0
- package/src/config.test.ts +317 -2
- package/src/config.ts +420 -40
- package/src/context.test.ts +136 -0
- package/src/context.ts +115 -0
- package/src/daemon.ts +17 -16
- package/src/doctor.test.ts +9 -7
- package/src/launchd.test.ts +1 -1
- package/src/launchd.ts +6 -6
- package/src/mcp-http.ts +75 -21
- package/src/mcp-install.test.ts +125 -0
- package/src/mcp-install.ts +60 -0
- package/src/mcp-tools.ts +34 -96
- package/src/module-config.ts +109 -0
- package/src/oauth.test.ts +345 -57
- package/src/oauth.ts +155 -35
- package/src/published.test.ts +2 -2
- package/src/routes.ts +209 -33
- package/src/routing.test.ts +817 -300
- package/src/routing.ts +204 -202
- package/src/scopes.test.ts +136 -0
- package/src/scopes.ts +105 -0
- package/src/scribe-env.test.ts +49 -0
- package/src/scribe-env.ts +33 -0
- package/src/server.ts +57 -5
- package/src/services-manifest.test.ts +140 -0
- package/src/services-manifest.ts +99 -0
- package/src/systemd.ts +3 -3
- package/src/token-store.ts +42 -9
- package/src/transcription-worker.test.ts +583 -0
- package/src/transcription-worker.ts +346 -0
- package/src/triggers.test.ts +191 -1
- package/src/triggers.ts +17 -2
- package/src/vault.test.ts +693 -77
- package/src/version.test.ts +1 -1
- package/.playwright-mcp/console-2026-04-14T04-17-25-395Z.log +0 -2
- package/.playwright-mcp/console-2026-04-14T04-18-11-767Z.log +0 -1
- package/.playwright-mcp/console-2026-04-14T04-19-07-733Z.log +0 -2
- package/.playwright-mcp/console-2026-04-14T04-20-45-440Z.log +0 -2
- package/.playwright-mcp/page-2026-04-14T04-17-25-536Z.yml +0 -1
- package/.playwright-mcp/page-2026-04-14T04-18-11-816Z.yml +0 -1
- package/.playwright-mcp/page-2026-04-14T04-18-31-674Z.yml +0 -211
- package/.playwright-mcp/page-2026-04-14T04-19-07-795Z.yml +0 -59
- package/.playwright-mcp/page-2026-04-14T04-19-36-239Z.yml +0 -232
- package/.playwright-mcp/page-2026-04-14T04-19-58-327Z.yml +0 -182
- package/.playwright-mcp/page-2026-04-14T04-20-10-517Z.yml +0 -91
- package/.playwright-mcp/page-2026-04-14T04-20-14-796Z.yml +0 -70
- package/.playwright-mcp/page-2026-04-14T04-20-45-509Z.yml +0 -59
- package/religions-abrahamic-filter.png +0 -0
- package/religions-buddhism-v2.png +0 -0
- package/religions-buddhism.png +0 -0
- package/religions-final.png +0 -0
- package/religions-v1.png +0 -0
- package/religions-v2.png +0 -0
- package/religions-zen.png +0 -0
- package/web/README.md +0 -73
- package/web/bun.lock +0 -827
- package/web/eslint.config.js +0 -23
- package/web/index.html +0 -15
- package/web/package.json +0 -36
- package/web/public/favicon.svg +0 -1
- package/web/public/icons.svg +0 -24
- package/web/src/App.tsx +0 -149
- package/web/src/Graph.tsx +0 -200
- package/web/src/NoteView.tsx +0 -155
- package/web/src/Sidebar.tsx +0 -186
- package/web/src/api.ts +0 -21
- package/web/src/index.css +0 -50
- package/web/src/main.tsx +0 -10
- package/web/src/types.ts +0 -37
- package/web/src/utils.ts +0 -107
- package/web/tsconfig.app.json +0 -25
- package/web/tsconfig.json +0 -7
- package/web/tsconfig.node.json +0 -24
- package/web/vite.config.ts +0 -16
package/web/src/Sidebar.tsx
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import type { GraphNode } from "./types";
|
|
2
|
-
import { FAMILY_COLORS, TYPE_COLORS } from "./utils";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
nodes: GraphNode[];
|
|
6
|
-
activeFilter: string | null;
|
|
7
|
-
onFilterChange: (tag: string | null) => void;
|
|
8
|
-
searchQuery: string;
|
|
9
|
-
onSearchChange: (q: string) => void;
|
|
10
|
-
searchResults: GraphNode[];
|
|
11
|
-
onSelect: (id: string) => void;
|
|
12
|
-
selectedId: string | null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const FAMILIES = [
|
|
16
|
-
{ tag: "family/abrahamic", label: "Abrahamic", color: FAMILY_COLORS.abrahamic },
|
|
17
|
-
{ tag: "family/dharmic", label: "Dharmic", color: FAMILY_COLORS.dharmic },
|
|
18
|
-
{ tag: "family/east-asian", label: "East Asian", color: FAMILY_COLORS["east-asian"] },
|
|
19
|
-
{ tag: "family/iranian", label: "Iranian", color: FAMILY_COLORS.iranian },
|
|
20
|
-
{ tag: "family/indigenous", label: "Indigenous", color: FAMILY_COLORS.indigenous },
|
|
21
|
-
{ tag: "family/nrm", label: "New Religious Movements", color: FAMILY_COLORS.nrm },
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const TYPES = [
|
|
25
|
-
{ tag: "type/tradition", label: "Traditions", color: "#ffffff" },
|
|
26
|
-
{ tag: "type/concept", label: "Concepts", color: TYPE_COLORS.concept },
|
|
27
|
-
{ tag: "type/figure", label: "Figures", color: TYPE_COLORS.figure },
|
|
28
|
-
{ tag: "type/text", label: "Texts", color: TYPE_COLORS.text },
|
|
29
|
-
{ tag: "type/practice", label: "Practices", color: TYPE_COLORS.practice },
|
|
30
|
-
{ tag: "type/school", label: "Schools", color: TYPE_COLORS.school },
|
|
31
|
-
{ tag: "type/theme", label: "Themes", color: TYPE_COLORS.theme },
|
|
32
|
-
{ tag: "type/moc", label: "Maps of Content", color: TYPE_COLORS.moc },
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
function FilterButton({
|
|
36
|
-
label,
|
|
37
|
-
color,
|
|
38
|
-
active,
|
|
39
|
-
count,
|
|
40
|
-
onClick,
|
|
41
|
-
}: {
|
|
42
|
-
label: string;
|
|
43
|
-
color: string;
|
|
44
|
-
active: boolean;
|
|
45
|
-
count: number;
|
|
46
|
-
onClick: () => void;
|
|
47
|
-
}) {
|
|
48
|
-
return (
|
|
49
|
-
<button
|
|
50
|
-
onClick={onClick}
|
|
51
|
-
className={`flex items-center gap-2 w-full text-left text-sm py-1 px-2 rounded transition-colors cursor-pointer ${
|
|
52
|
-
active
|
|
53
|
-
? "bg-surface-2 text-white"
|
|
54
|
-
: "text-text-muted hover:text-text hover:bg-surface-2/50"
|
|
55
|
-
}`}
|
|
56
|
-
>
|
|
57
|
-
<span
|
|
58
|
-
className="w-2 h-2 rounded-full flex-shrink-0"
|
|
59
|
-
style={{ background: color }}
|
|
60
|
-
/>
|
|
61
|
-
<span className="flex-1 truncate">{label}</span>
|
|
62
|
-
<span className="text-xs opacity-50">{count}</span>
|
|
63
|
-
</button>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export default function Sidebar({
|
|
68
|
-
nodes,
|
|
69
|
-
activeFilter,
|
|
70
|
-
onFilterChange,
|
|
71
|
-
searchQuery,
|
|
72
|
-
onSearchChange,
|
|
73
|
-
searchResults,
|
|
74
|
-
onSelect,
|
|
75
|
-
selectedId,
|
|
76
|
-
}: Props) {
|
|
77
|
-
const tagCounts = new Map<string, number>();
|
|
78
|
-
for (const n of nodes) {
|
|
79
|
-
for (const t of n.tags) {
|
|
80
|
-
tagCounts.set(t, (tagCounts.get(t) ?? 0) + 1);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<div className="w-[240px] min-w-[200px] h-screen bg-surface border-r border-border flex flex-col overflow-hidden">
|
|
86
|
-
{/* Header */}
|
|
87
|
-
<div className="p-4 pb-3 border-b border-border">
|
|
88
|
-
<h1 className="text-sm font-semibold text-white tracking-tight">
|
|
89
|
-
Religions of the World
|
|
90
|
-
</h1>
|
|
91
|
-
<p className="text-xs text-text-muted mt-0.5">Knowledge Graph</p>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
{/* Search */}
|
|
95
|
-
<div className="px-3 pt-3 pb-2">
|
|
96
|
-
<input
|
|
97
|
-
type="text"
|
|
98
|
-
value={searchQuery}
|
|
99
|
-
onChange={(e) => onSearchChange(e.target.value)}
|
|
100
|
-
placeholder="Search notes..."
|
|
101
|
-
className="w-full bg-surface-2 border border-border rounded px-2.5 py-1.5 text-sm text-text placeholder:text-text-muted/50 outline-none focus:border-accent/50 transition-colors"
|
|
102
|
-
/>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
{/* Search results */}
|
|
106
|
-
{searchQuery.trim() && (
|
|
107
|
-
<div className="px-2 pb-2 border-b border-border max-h-[200px] overflow-y-auto">
|
|
108
|
-
{searchResults.length === 0 ? (
|
|
109
|
-
<div className="text-xs text-text-muted px-2 py-1">No results</div>
|
|
110
|
-
) : (
|
|
111
|
-
searchResults.map((n) => (
|
|
112
|
-
<button
|
|
113
|
-
key={n.id}
|
|
114
|
-
onClick={() => onSelect(n.id)}
|
|
115
|
-
className={`w-full text-left text-sm py-1 px-2 rounded truncate cursor-pointer transition-colors ${
|
|
116
|
-
n.id === selectedId
|
|
117
|
-
? "bg-surface-2 text-white"
|
|
118
|
-
: "text-text-muted hover:text-text hover:bg-surface-2/50"
|
|
119
|
-
}`}
|
|
120
|
-
>
|
|
121
|
-
{n.label}
|
|
122
|
-
<span className="text-xs opacity-40 ml-1">{n.type}</span>
|
|
123
|
-
</button>
|
|
124
|
-
))
|
|
125
|
-
)}
|
|
126
|
-
</div>
|
|
127
|
-
)}
|
|
128
|
-
|
|
129
|
-
{/* Filters */}
|
|
130
|
-
<div className="flex-1 overflow-y-auto px-2 py-3 space-y-4">
|
|
131
|
-
{/* Clear filter */}
|
|
132
|
-
{activeFilter && (
|
|
133
|
-
<button
|
|
134
|
-
onClick={() => onFilterChange(null)}
|
|
135
|
-
className="flex items-center gap-1.5 text-xs text-accent px-2 py-1 hover:underline cursor-pointer"
|
|
136
|
-
>
|
|
137
|
-
× Clear filter
|
|
138
|
-
</button>
|
|
139
|
-
)}
|
|
140
|
-
|
|
141
|
-
{/* By Family */}
|
|
142
|
-
<div>
|
|
143
|
-
<div className="text-[10px] font-semibold text-text-muted uppercase tracking-widest px-2 mb-1">
|
|
144
|
-
By Family
|
|
145
|
-
</div>
|
|
146
|
-
{FAMILIES.map((f) => (
|
|
147
|
-
<FilterButton
|
|
148
|
-
key={f.tag}
|
|
149
|
-
label={f.label}
|
|
150
|
-
color={f.color}
|
|
151
|
-
active={activeFilter === f.tag}
|
|
152
|
-
count={tagCounts.get(f.tag) ?? 0}
|
|
153
|
-
onClick={() =>
|
|
154
|
-
onFilterChange(activeFilter === f.tag ? null : f.tag)
|
|
155
|
-
}
|
|
156
|
-
/>
|
|
157
|
-
))}
|
|
158
|
-
</div>
|
|
159
|
-
|
|
160
|
-
{/* By Type */}
|
|
161
|
-
<div>
|
|
162
|
-
<div className="text-[10px] font-semibold text-text-muted uppercase tracking-widest px-2 mb-1">
|
|
163
|
-
By Type
|
|
164
|
-
</div>
|
|
165
|
-
{TYPES.map((t) => (
|
|
166
|
-
<FilterButton
|
|
167
|
-
key={t.tag}
|
|
168
|
-
label={t.label}
|
|
169
|
-
color={t.color}
|
|
170
|
-
active={activeFilter === t.tag}
|
|
171
|
-
count={tagCounts.get(t.tag) ?? 0}
|
|
172
|
-
onClick={() =>
|
|
173
|
-
onFilterChange(activeFilter === t.tag ? null : t.tag)
|
|
174
|
-
}
|
|
175
|
-
/>
|
|
176
|
-
))}
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
{/* Footer */}
|
|
181
|
-
<div className="p-3 border-t border-border text-[10px] text-text-muted/50 text-center">
|
|
182
|
-
Powered by Parachute Vault
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
}
|
package/web/src/api.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { Note, Tag } from "./types";
|
|
2
|
-
|
|
3
|
-
const BASE = "/api";
|
|
4
|
-
|
|
5
|
-
export async function fetchAllNotes(): Promise<Note[]> {
|
|
6
|
-
const res = await fetch(`${BASE}/notes?include_content=true&limit=500`);
|
|
7
|
-
if (!res.ok) throw new Error(`Failed to fetch notes: ${res.status}`);
|
|
8
|
-
return res.json();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export async function fetchTags(): Promise<Tag[]> {
|
|
12
|
-
const res = await fetch(`${BASE}/tags`);
|
|
13
|
-
if (!res.ok) throw new Error(`Failed to fetch tags: ${res.status}`);
|
|
14
|
-
return res.json();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function searchNotes(q: string): Promise<Note[]> {
|
|
18
|
-
const res = await fetch(`${BASE}/search?q=${encodeURIComponent(q)}`);
|
|
19
|
-
if (!res.ok) throw new Error(`Failed to search: ${res.status}`);
|
|
20
|
-
return res.json();
|
|
21
|
-
}
|
package/web/src/index.css
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
2
|
-
|
|
3
|
-
@theme {
|
|
4
|
-
--color-bg: #0a0a0f;
|
|
5
|
-
--color-surface: #111118;
|
|
6
|
-
--color-surface-2: #1a1a24;
|
|
7
|
-
--color-border: #2a2a3a;
|
|
8
|
-
--color-text: #d4d4e0;
|
|
9
|
-
--color-text-muted: #7878a0;
|
|
10
|
-
--color-accent: #7c8aff;
|
|
11
|
-
|
|
12
|
-
--color-abrahamic: #5b8def;
|
|
13
|
-
--color-dharmic: #e8a44a;
|
|
14
|
-
--color-east-asian: #4ecdc4;
|
|
15
|
-
--color-iranian: #c45bef;
|
|
16
|
-
--color-indigenous: #5aaf5a;
|
|
17
|
-
--color-nrm: #ef5b8d;
|
|
18
|
-
--color-default: #6a6a8a;
|
|
19
|
-
|
|
20
|
-
--font-serif: "Newsreader", Georgia, serif;
|
|
21
|
-
--font-sans: "Inter", system-ui, sans-serif;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
html {
|
|
25
|
-
background: var(--color-bg);
|
|
26
|
-
color: var(--color-text);
|
|
27
|
-
font-family: var(--font-sans);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
body {
|
|
31
|
-
margin: 0;
|
|
32
|
-
overflow: hidden;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/* Markdown rendering */
|
|
36
|
-
.note-content h1 { font: 700 1.75rem/1.2 var(--font-serif); margin-bottom: 0.75rem; color: white; }
|
|
37
|
-
.note-content h2 { font: 600 1.2rem/1.3 var(--font-sans); margin: 1.75rem 0 0.5rem; color: #bbbbd0; border-bottom: 1px solid var(--color-border); padding-bottom: 0.35rem; }
|
|
38
|
-
.note-content h3 { font: 600 1.05rem/1.3 var(--font-sans); margin: 1.25rem 0 0.4rem; color: #a0a0b8; }
|
|
39
|
-
.note-content p { margin: 0.5rem 0; line-height: 1.7; font-family: var(--font-serif); font-size: 1.02rem; }
|
|
40
|
-
.note-content ul, .note-content ol { margin: 0.5rem 0; padding-left: 1.25rem; }
|
|
41
|
-
.note-content li { margin: 0.2rem 0; line-height: 1.6; font-family: var(--font-serif); font-size: 1.02rem; }
|
|
42
|
-
.note-content strong { color: white; font-weight: 600; }
|
|
43
|
-
.note-content em { color: #b0b0c8; }
|
|
44
|
-
.note-content blockquote { border-left: 3px solid var(--color-accent); padding-left: 1rem; margin: 1rem 0; color: var(--color-text-muted); }
|
|
45
|
-
.note-content code { background: var(--color-surface-2); padding: 0.12rem 0.35rem; border-radius: 3px; font-size: 0.88em; }
|
|
46
|
-
|
|
47
|
-
/* Scrollbar */
|
|
48
|
-
::-webkit-scrollbar { width: 5px; }
|
|
49
|
-
::-webkit-scrollbar-track { background: transparent; }
|
|
50
|
-
::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
|
package/web/src/main.tsx
DELETED
package/web/src/types.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export interface NoteIndex {
|
|
2
|
-
id: string;
|
|
3
|
-
path?: string;
|
|
4
|
-
tags: string[];
|
|
5
|
-
createdAt: string;
|
|
6
|
-
updatedAt: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface Note extends NoteIndex {
|
|
10
|
-
content: string;
|
|
11
|
-
metadata?: Record<string, unknown>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface GraphNode {
|
|
15
|
-
id: string;
|
|
16
|
-
path: string;
|
|
17
|
-
label: string;
|
|
18
|
-
type: string; // tradition, concept, figure, text, practice, school, theme, moc
|
|
19
|
-
family: string; // abrahamic, dharmic, east-asian, iranian, indigenous, nrm, ""
|
|
20
|
-
tags: string[];
|
|
21
|
-
x?: number;
|
|
22
|
-
y?: number;
|
|
23
|
-
fx?: number | null;
|
|
24
|
-
fy?: number | null;
|
|
25
|
-
vx?: number;
|
|
26
|
-
vy?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface GraphEdge {
|
|
30
|
-
source: string | GraphNode;
|
|
31
|
-
target: string | GraphNode;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface Tag {
|
|
35
|
-
name: string;
|
|
36
|
-
count: number;
|
|
37
|
-
}
|
package/web/src/utils.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import type { Note, GraphNode, GraphEdge } from "./types";
|
|
2
|
-
|
|
3
|
-
// Extract [[wikilinks]] from note content and resolve to note IDs
|
|
4
|
-
const WIKILINK_RE = /\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g;
|
|
5
|
-
|
|
6
|
-
export function extractWikilinks(content: string): string[] {
|
|
7
|
-
const links: string[] = [];
|
|
8
|
-
let m: RegExpExecArray | null;
|
|
9
|
-
while ((m = WIKILINK_RE.exec(content)) !== null) {
|
|
10
|
-
links.push(m[1]);
|
|
11
|
-
}
|
|
12
|
-
return links;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function buildGraph(notes: Note[]): { nodes: GraphNode[]; edges: GraphEdge[] } {
|
|
16
|
-
const pathToId = new Map<string, string>();
|
|
17
|
-
for (const n of notes) {
|
|
18
|
-
if (n.path) pathToId.set(n.path, n.id);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const nodes: GraphNode[] = notes.map((n) => ({
|
|
22
|
-
id: n.id,
|
|
23
|
-
path: n.path ?? n.id,
|
|
24
|
-
label: labelFromPath(n.path ?? n.id),
|
|
25
|
-
type: getType(n.tags),
|
|
26
|
-
family: getFamily(n.tags),
|
|
27
|
-
tags: n.tags,
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
const nodeIds = new Set(nodes.map((n) => n.id));
|
|
31
|
-
const edgeSet = new Set<string>();
|
|
32
|
-
const edges: GraphEdge[] = [];
|
|
33
|
-
|
|
34
|
-
for (const n of notes) {
|
|
35
|
-
const targets = extractWikilinks(n.content);
|
|
36
|
-
for (const target of targets) {
|
|
37
|
-
const targetId = pathToId.get(target);
|
|
38
|
-
if (targetId && targetId !== n.id && nodeIds.has(targetId)) {
|
|
39
|
-
const key = `${n.id}->${targetId}`;
|
|
40
|
-
if (!edgeSet.has(key)) {
|
|
41
|
-
edgeSet.add(key);
|
|
42
|
-
edges.push({ source: n.id, target: targetId });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return { nodes, edges };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function labelFromPath(path: string): string {
|
|
52
|
-
const parts = path.split("/");
|
|
53
|
-
return parts[parts.length - 1];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getType(tags: string[]): string {
|
|
57
|
-
for (const t of tags) {
|
|
58
|
-
if (t.startsWith("type/")) return t.slice(5);
|
|
59
|
-
}
|
|
60
|
-
return "other";
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function getFamily(tags: string[]): string {
|
|
64
|
-
for (const t of tags) {
|
|
65
|
-
if (t.startsWith("family/")) return t.slice(7);
|
|
66
|
-
}
|
|
67
|
-
return "";
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const FAMILY_COLORS: Record<string, string> = {
|
|
71
|
-
abrahamic: "#5b8def",
|
|
72
|
-
dharmic: "#e8a44a",
|
|
73
|
-
"east-asian": "#4ecdc4",
|
|
74
|
-
iranian: "#c45bef",
|
|
75
|
-
indigenous: "#5aaf5a",
|
|
76
|
-
nrm: "#ef5b8d",
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const TYPE_COLORS: Record<string, string> = {
|
|
80
|
-
tradition: "#ffffff",
|
|
81
|
-
concept: "#8888a0",
|
|
82
|
-
figure: "#e8a44a",
|
|
83
|
-
text: "#5b8def",
|
|
84
|
-
practice: "#4ecdc4",
|
|
85
|
-
school: "#c45bef",
|
|
86
|
-
theme: "#ef5b8d",
|
|
87
|
-
moc: "#ffffff",
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export function nodeColor(node: GraphNode): string {
|
|
91
|
-
// For traditions/mocs, use family color
|
|
92
|
-
if (node.type === "tradition" || node.type === "moc") {
|
|
93
|
-
return FAMILY_COLORS[node.family] ?? "#6a6a8a";
|
|
94
|
-
}
|
|
95
|
-
// For others, try family first, then type
|
|
96
|
-
if (node.family && FAMILY_COLORS[node.family]) {
|
|
97
|
-
return FAMILY_COLORS[node.family];
|
|
98
|
-
}
|
|
99
|
-
return TYPE_COLORS[node.type] ?? "#6a6a8a";
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function nodeRadius(node: GraphNode): number {
|
|
103
|
-
if (node.type === "moc") return 8;
|
|
104
|
-
if (node.type === "tradition") return 6;
|
|
105
|
-
if (node.type === "theme") return 5;
|
|
106
|
-
return 3.5;
|
|
107
|
-
}
|
package/web/tsconfig.app.json
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
-
"target": "es2023",
|
|
5
|
-
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
|
6
|
-
"module": "esnext",
|
|
7
|
-
"types": ["vite/client"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
"jsx": "react-jsx",
|
|
17
|
-
|
|
18
|
-
/* Linting */
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"erasableSyntaxOnly": true,
|
|
22
|
-
"noFallthroughCasesInSwitch": true
|
|
23
|
-
},
|
|
24
|
-
"include": ["src"]
|
|
25
|
-
}
|
package/web/tsconfig.json
DELETED
package/web/tsconfig.node.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
-
"target": "es2023",
|
|
5
|
-
"lib": ["ES2023"],
|
|
6
|
-
"module": "esnext",
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
/* Linting */
|
|
18
|
-
"noUnusedLocals": true,
|
|
19
|
-
"noUnusedParameters": true,
|
|
20
|
-
"erasableSyntaxOnly": true,
|
|
21
|
-
"noFallthroughCasesInSwitch": true
|
|
22
|
-
},
|
|
23
|
-
"include": ["vite.config.ts"]
|
|
24
|
-
}
|
package/web/vite.config.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "vite";
|
|
2
|
-
import react from "@vitejs/plugin-react";
|
|
3
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
plugins: [react(), tailwindcss()],
|
|
7
|
-
server: {
|
|
8
|
-
allowedHosts: ['mbp.taildf9ce2.ts.net'],
|
|
9
|
-
proxy: {
|
|
10
|
-
"/api": {
|
|
11
|
-
target: "http://localhost:1940/vaults/religions",
|
|
12
|
-
changeOrigin: true,
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
});
|