mirror of
https://github.com/yashmurty/obsidian-people-graph.git
synced 2026-07-22 06:08:45 +00:00
fix: address Obsidian plugin review feedback
- Use sentence case for UI text - Fix async/await and unhandled promises - Remove style element from export, use CSS classes - Replace inline styles with CSS classes - Fix any types with proper D3 generics - Remove plugin prefix from command ID/name - Remove detachLeavesOfType from onunload - Use arrow functions to avoid this scoping issues Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
47fbafcf11
commit
a065c7f7d3
5 changed files with 45 additions and 38 deletions
|
|
@ -19,15 +19,15 @@ export class PeopleGraphView extends ItemView {
|
|||
}
|
||||
|
||||
getDisplayText(): string {
|
||||
return "People Graph";
|
||||
return "People graph";
|
||||
}
|
||||
|
||||
getIcon(): string {
|
||||
return "users";
|
||||
}
|
||||
|
||||
async onOpen() {
|
||||
this.render();
|
||||
async onOpen(): Promise<void> {
|
||||
await this.render();
|
||||
|
||||
// Export button in view header
|
||||
this.addAction("download", "Export as PNG", async () => {
|
||||
|
|
@ -49,18 +49,18 @@ export class PeopleGraphView extends ItemView {
|
|||
// Re-render when a note's frontmatter changes
|
||||
this.registerEvent(
|
||||
this.app.metadataCache.on("changed", () => {
|
||||
this.render();
|
||||
void this.render();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async render() {
|
||||
async render(): Promise<void> {
|
||||
const container = this.containerEl.children[1] as HTMLElement;
|
||||
const people = await indexPeople(this.app, this.plugin.settings);
|
||||
renderGraph(container, people, this.plugin.settings, this.app);
|
||||
}
|
||||
|
||||
async onClose() {
|
||||
async onClose(): Promise<void> {
|
||||
const container = this.containerEl.children[1] as HTMLElement;
|
||||
container.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,10 @@ export async function exportGraphAsPng(container: HTMLElement): Promise<Blob | n
|
|||
clone.setAttribute("height", String(height));
|
||||
clone.setAttribute("viewBox", svgEl.getAttribute("viewBox") ?? `0 0 ${bbox.width} ${bbox.height}`);
|
||||
|
||||
// Inline computed styles so they survive serialization
|
||||
const styles = document.createElement("style");
|
||||
styles.textContent = `
|
||||
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
|
||||
`;
|
||||
clone.prepend(styles);
|
||||
// Set font-family directly on text elements instead of using a style element
|
||||
clone.querySelectorAll("text").forEach((textEl) => {
|
||||
textEl.setAttribute("font-family", "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif");
|
||||
});
|
||||
|
||||
const serializer = new XMLSerializer();
|
||||
const svgString = serializer.serializeToString(clone);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as d3 from "d3";
|
||||
import { Notice } from "obsidian";
|
||||
import type { App } from "obsidian";
|
||||
import type { App, TFile } from "obsidian";
|
||||
import type { PersonNode, PeopleGraphSettings } from "../types";
|
||||
|
||||
interface SimNode extends d3.SimulationNodeDatum {
|
||||
|
|
@ -15,7 +15,8 @@ interface SimLink extends d3.SimulationLinkDatum<SimNode> {
|
|||
|
||||
const NODE_RADIUS = 24;
|
||||
|
||||
function appendAvatarSilhouette(el: d3.Selection<any, any, any, any>) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function appendAvatarSilhouette(el: d3.Selection<SVGGElement, any, any, any>) {
|
||||
// Head
|
||||
el.append("circle")
|
||||
.attr("cy", -4)
|
||||
|
|
@ -125,8 +126,7 @@ export function renderGraph(
|
|||
}
|
||||
|
||||
// Create SVG — fills container and resizes with it
|
||||
container.style.position = "relative";
|
||||
container.style.overflow = "hidden";
|
||||
container.addClass("people-graph-container");
|
||||
|
||||
const svg = d3
|
||||
.select(container)
|
||||
|
|
@ -205,18 +205,19 @@ export function renderGraph(
|
|||
|
||||
// Free tier: dim nodes beyond limit (skip center node)
|
||||
const maxFree = settings.maxFreeNodes;
|
||||
const nodeElements = nodeSelection.nodes();
|
||||
let personIndex = 0;
|
||||
nodeSelection.each(function (d) {
|
||||
nodeSelection.each((d, i) => {
|
||||
if (d.isCenter) return;
|
||||
if (personIndex >= maxFree) {
|
||||
d3.select(this).attr("opacity", 0.3);
|
||||
d3.select(nodeElements[i]).attr("opacity", 0.3);
|
||||
}
|
||||
personIndex++;
|
||||
});
|
||||
|
||||
// Render node visuals
|
||||
nodeSelection.each(function (d, i) {
|
||||
const el = d3.select(this);
|
||||
nodeSelection.each((d, i) => {
|
||||
const el = d3.select(nodeElements[i]);
|
||||
|
||||
if (d.isCenter) {
|
||||
const centerR = NODE_RADIUS + 4;
|
||||
|
|
@ -331,17 +332,7 @@ export function renderGraph(
|
|||
const tooltip = d3
|
||||
.select(container)
|
||||
.append("div")
|
||||
.attr("class", "people-graph-tooltip")
|
||||
.style("position", "absolute")
|
||||
.style("display", "none")
|
||||
.style("background", "#ffffff")
|
||||
.style("border", "1px solid #e0e0e0")
|
||||
.style("border-radius", "6px")
|
||||
.style("padding", "8px 12px")
|
||||
.style("font-size", "12px")
|
||||
.style("pointer-events", "none")
|
||||
.style("z-index", "100")
|
||||
.style("box-shadow", "0 2px 8px rgba(0,0,0,0.15)");
|
||||
.attr("class", "people-graph-tooltip");
|
||||
|
||||
nodeSelection
|
||||
.on("mouseenter", (event, d) => {
|
||||
|
|
@ -381,7 +372,7 @@ export function renderGraph(
|
|||
}
|
||||
const file = app.vault.getAbstractFileByPath(d.person.id);
|
||||
if (file) {
|
||||
app.workspace.getLeaf("tab").openFile(file as any);
|
||||
void app.workspace.getLeaf("tab").openFile(file as TFile);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
12
src/main.ts
12
src/main.ts
|
|
@ -14,23 +14,23 @@ export default class PeopleGraphPlugin extends Plugin {
|
|||
(leaf) => new PeopleGraphView(leaf, this)
|
||||
);
|
||||
|
||||
this.addRibbonIcon("users", "Open People Graph", () => {
|
||||
this.activateView();
|
||||
this.addRibbonIcon("users", "Open people graph", () => {
|
||||
void this.activateView();
|
||||
});
|
||||
|
||||
this.addSettingTab(new PeopleGraphSettingTab(this.app, this));
|
||||
|
||||
this.addCommand({
|
||||
id: "open-people-graph",
|
||||
name: "Open People Graph",
|
||||
id: "open",
|
||||
name: "Open graph",
|
||||
callback: () => {
|
||||
this.activateView();
|
||||
void this.activateView();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
this.app.workspace.detachLeavesOfType(VIEW_TYPE_PEOPLE_GRAPH);
|
||||
// no-op: don't detach leaves so user layout is preserved
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
|
|
|
|||
18
styles.css
18
styles.css
|
|
@ -1 +1,19 @@
|
|||
/* People Graph plugin styles */
|
||||
|
||||
.people-graph-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.people-graph-tooltip {
|
||||
position: absolute;
|
||||
display: none;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
padding: 8px 12px;
|
||||
font-size: 12px;
|
||||
pointer-events: none;
|
||||
z-index: 100;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue