This commit is contained in:
Team3
2026-05-22 00:27:57 +02:00
parent b7759d6542
commit 93bc13dc78
3 changed files with 33 additions and 65 deletions

View File

@@ -7,8 +7,6 @@ import {
normalizePath,
} from "obsidian";
import cytoscape, { Core, NodeSingular } from "cytoscape";
// @ts-ignore — no types for cytoscape-fcose
import fcose from "cytoscape-fcose";
import {
VIEW_TYPE_PROJECT_DETAILS_VIEW,
VIEW_TYPE_PROJECT_VIEW,
@@ -30,14 +28,12 @@ import {
import { menu, breadcrumb, emptyState, openMarkdown } from "../ui";
import { NameModal } from "../modals/NameModal";
cytoscape.use(fcose);
export interface ProjectDetailsState extends Record<string, unknown> {
project: string;
}
const NAME_RX = /^[^\\/:*?"<>|]+$/;
const ROOT_ID = ":root:";
const ROOT_ID = "__pk_root__";
function validateName(name: string, taken: string[], current?: string): string | null {
if (!name) return "Name darf nicht leer sein.";
@@ -155,6 +151,7 @@ export class ProjectDetailsView extends ItemView {
const styles = getComputedStyle(this.containerEl);
const textColor = styles.getPropertyValue("--text-normal").trim() || "#222";
const borderColor = styles.getPropertyValue("--background-modifier-border").trim() || "#ccc";
const edgeColor = styles.getPropertyValue("--text-muted").trim() || "#888";
const accent = styles.getPropertyValue("--interactive-accent").trim() || "#7b6cd9";
const bgNode = styles.getPropertyValue("--background-primary").trim() || "#fff";
@@ -201,28 +198,25 @@ export class ProjectDetailsView extends ItemView {
{
selector: "edge",
style: {
width: 1.5,
"line-color": borderColor,
"target-arrow-color": borderColor,
width: 2,
"line-color": edgeColor,
"target-arrow-color": edgeColor,
"target-arrow-shape": "triangle",
"curve-style": "bezier",
},
},
],
layout: {
name: "fcose",
// @ts-ignore — fcose options not in cytoscape types
quality: "default",
randomize: true,
animate: false,
name: "concentric",
concentric: (node) => -((node.data("depth") as number) ?? 0),
levelWidth: () => 1,
minNodeSpacing: 60,
// @ts-ignore — spacingFactor exists in concentric layout
spacingFactor: 1.4,
fit: true,
padding: 30,
nodeRepulsion: 8000,
idealEdgeLength: 100,
gravity: 0.25,
fixedNodeConstraint: [
{ nodeId: ROOT_ID, position: { x: 0, y: 0 } },
],
startAngle: -Math.PI / 2,
clockwise: true,
},
});
@@ -231,15 +225,17 @@ export class ProjectDetailsView extends ItemView {
private treeToElements(tree: NodeTree): cytoscape.ElementDefinition[] {
const els: cytoscape.ElementDefinition[] = [];
els.push({ data: { id: ROOT_ID, label: tree.name } });
const walk = (node: NodeTree, parentId: string) => {
for (const child of node.children) {
els.push({ data: { id: child.path, label: child.name } });
els.push({ data: { id: `${parentId}>${child.path}`, source: parentId, target: child.path } });
walk(child, child.path);
els.push({ data: { id: ROOT_ID, label: tree.name, path: tree.path, depth: 0 } });
let counter = 0;
const walk = (children: NodeTree[], parentId: string, depth: number) => {
for (const child of children) {
const id = `n${counter++}`;
els.push({ data: { id, label: child.name, path: child.path, depth } });
els.push({ data: { source: parentId, target: id } });
walk(child.children, id, depth + 1);
}
};
walk(tree, ROOT_ID);
walk(tree.children, ROOT_ID, 1);
return els;
}
@@ -249,28 +245,27 @@ export class ProjectDetailsView extends ItemView {
cy.on("tap", "node", (ev) => {
const node = ev.target as NodeSingular;
const id = node.id();
if (id === ROOT_ID) {
if (node.id() === ROOT_ID) {
const corePath = normalizePath(`${projectPath(this.project)}/${CORE_FILE}`);
void openMarkdown(this.app, corePath, this.leaf);
return;
}
void openMarkdown(this.app, nodeMdPath(id), this.leaf);
const path = node.data("path") as string;
void openMarkdown(this.app, nodeMdPath(path), this.leaf);
});
cy.on("cxttap", "node", (ev) => {
const node = ev.target as NodeSingular;
const id = node.id();
const originalEvent = ev.originalEvent as MouseEvent;
originalEvent.preventDefault();
if (id === ROOT_ID) {
if (node.id() === ROOT_ID) {
const parent = projectPath(this.project);
menu(originalEvent, [
{ title: "Neuer Child-Node", icon: "plus", onClick: () => this.openCreateChild(parent) },
]);
return;
}
const folder = id;
const folder = node.data("path") as string;
const parentPath = folder.substring(0, folder.lastIndexOf("/"));
const currentName = folder.split("/").pop() ?? "";
menu(originalEvent, [
@@ -320,8 +315,10 @@ export class ProjectDetailsView extends ItemView {
if (start) node.position(start);
return;
}
const sourcePath = node.id();
const targetPath = target.id() === ROOT_ID ? projectPath(this.project) : target.id();
const sourcePath = node.data("path") as string;
const targetPath = target.id() === ROOT_ID
? projectPath(this.project)
: (target.data("path") as string);
const currentParent = sourcePath.substring(0, sourcePath.lastIndexOf("/"));
if (currentParent === targetPath) {
if (start) node.position(start);