Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
Add support for highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
marcusolsson committed Oct 6, 2021
1 parent 8ad431b commit a929d97
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 88 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "obsidian-vale",
"name": "Vale",
"version": "0.6.0",
"version": "0.7.0",
"minAppVersion": "0.9.12",
"description": "A Vale client for Obsidian.",
"author": "Marcus Olsson",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-vale",
"version": "0.6.0",
"version": "0.7.0",
"description": "A Vale client for Obsidian.",
"main": "main.js",
"scripts": {
Expand Down
7 changes: 6 additions & 1 deletion src/EventBus.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { debug } from "./debug";

type EventType = "ready" | "check";
type EventType =
| "ready"
| "check"
| "select-alert"
| "deselect-alert"
| "alerts";

// The main purpose of the event bus is to issue commands to the React
// application.
Expand Down
23 changes: 18 additions & 5 deletions src/ValeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { ValeApp } from "./components/ValeApp";
import { AppContext, SettingsContext } from "./context";
import { timed } from "./debug";
import { EventBus } from "./EventBus";
import { ValeRunner } from "./ValeRunner";
import { ValeSettings } from "./types";
import { ValeAlert, ValeSettings } from "./types";
import { ValeRunner } from "./vale/ValeRunner";

export const VIEW_TYPE_VALE = "vale";

Expand All @@ -19,11 +19,20 @@ export class ValeView extends ItemView {
private ready: boolean;
private unregisterReady: () => void;

constructor(leaf: WorkspaceLeaf, settings: ValeSettings, runner: ValeRunner) {
private onAlertClick: (alert: ValeAlert) => void;

constructor(
leaf: WorkspaceLeaf,
settings: ValeSettings,
runner: ValeRunner,
eventBus: EventBus,
onAlertClick: (alert: ValeAlert) => void
) {
super(leaf);
this.settings = settings;
this.runner = runner;
this.eventBus = new EventBus();
this.eventBus = eventBus;
this.onAlertClick = onAlertClick;
}

getViewType(): string {
Expand All @@ -50,7 +59,11 @@ export class ValeView extends ItemView {
<AppContext.Provider value={this.app}>
<SettingsContext.Provider value={this.settings}>
<div className="obsidian-vale">
<ValeApp runner={this.runner} eventBus={this.eventBus} />
<ValeApp
runner={this.runner}
eventBus={this.eventBus}
onAlertClick={this.onAlertClick}
/>
</div>
</SettingsContext.Provider>
</AppContext.Provider>,
Expand Down
32 changes: 22 additions & 10 deletions src/components/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,31 @@ import { Icon } from "./Icon";
interface Props {
alert: ValeAlert;
onClick: (alert: ValeAlert) => void;
highlight: boolean;
}

export const Alert = ({ alert, onClick }: Props): React.ReactElement => {
const cb: React.MouseEventHandler<HTMLDivElement> = (
e: React.MouseEvent<HTMLDivElement>
) => {
// Ignore click when clicking the link.
if (e.currentTarget.nodeName === "DIV") {
onClick(alert);
}
};
export const Alert = ({
alert,
onClick,
highlight,
}: Props): React.ReactElement => {
const ref = React.useRef<HTMLDivElement>();

if (ref.current && highlight) {
ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
}

return (
<div className="alert" onClick={cb}>
<div
ref={ref}
className={`alert${highlight ? " alert--highlighted" : ""}`}
onClick={(e) => {
// Ignore click when clicking the link.
if (e.currentTarget.nodeName === "DIV") {
onClick(alert);
}
}}
>
<div className="alert__header">
<div
className={`alert__severity alert__severity-text--${alert.Severity}`}
Expand Down
47 changes: 9 additions & 38 deletions src/components/AlertList.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,27 @@
import { MarkdownView } from "obsidian";
import * as React from "react";
import { useApp } from "../hooks";
import { ValeAlert } from "../types";
import { Alert } from "./Alert";

interface Props {
alerts: ValeAlert[];
highlight?: ValeAlert;
onClick: (alert: ValeAlert) => void;
}

export const AlertList = ({ alerts }: Props): React.ReactElement => {
const { workspace } = useApp();

export const AlertList = ({
alerts,
highlight,
onClick,
}: Props): React.ReactElement => {
return (
<>
{alerts?.map((alert, key) => {
return (
<Alert
key={key}
alert={alert}
onClick={(alert) => {
const view = workspace.getActiveViewOfType(MarkdownView);
const editor = view.sourceMode.cmEditor;

if (view.getMode() === "source") {
// Clear previously highlighted alert.
editor
.getAllMarks()
.filter((mark) =>
mark.className.contains("vale-underline-highlight")
)
.forEach((mark) => mark.clear());

editor.markText(
{
line: alert.Line - 1,
ch: alert.Span[0] - 1,
},
{
line: alert.Line - 1,
ch: alert.Span[1],
},
{
className: "vale-underline-highlight",
}
);

editor.scrollIntoView({
line: alert.Line - 1,
ch: alert.Span[0] - 1,
});
}
}}
onClick={onClick}
highlight={highlight === alert}
/>
);
})}
Expand Down
59 changes: 35 additions & 24 deletions src/components/ValeApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ import { Icon } from "./Icon";
interface Props {
runner: ValeRunner;
eventBus: EventBus;
onAlertClick: (alert: ValeAlert) => void;
}

interface CheckReport {
results: ValeAlert[];
errors?: React.ReactNode;
}

export const ValeApp = ({ runner, eventBus }: Props): React.ReactElement => {
export const ValeApp = ({
runner,
eventBus,
onAlertClick,
}: Props): React.ReactElement => {
const [loading, setLoading] = React.useState(false);
const [highlightAlert, setHighlightAlert] = React.useState<ValeAlert>();

const [report, setReport] = React.useState<CheckReport>({
results: [],
});
Expand Down Expand Up @@ -57,12 +64,11 @@ export const ValeApp = ({ runner, eventBus }: Props): React.ReactElement => {
return runner
.run(text, format)
.then((response) => {
checked(() =>
setReport({
...report,
results: Object.values(response)[0],
})
);
checked(() => {
const results = Object.values(response)[0];
setReport({ ...report, results });
eventBus.dispatch("alerts", results);
});
})
.catch((err) => {
if (err instanceof Error) {
Expand Down Expand Up @@ -91,6 +97,21 @@ export const ValeApp = ({ runner, eventBus }: Props): React.ReactElement => {
});
};

React.useEffect(() => {
const unr = eventBus.on("select-alert", (alert: ValeAlert) => {
setHighlightAlert(alert);
});

const unr2 = eventBus.on("deselect-alert", () => {
setHighlightAlert(undefined);
});

return () => {
unr();
unr2();
};
}, [report]);

React.useEffect(() => {
let cancel = false;

Expand Down Expand Up @@ -127,23 +148,13 @@ export const ValeApp = ({ runner, eventBus }: Props): React.ReactElement => {
}

if (report.results) {
const editor = view.sourceMode.cmEditor;

// Clear marks from previous check.
editor.getAllMarks().forEach((mark) => mark.clear());

report.results.forEach((alert: ValeAlert) => {
editor.markText(
{ line: alert.Line - 1, ch: alert.Span[0] - 1 },
{ line: alert.Line - 1, ch: alert.Span[1] },
{
className: `vale-underline vale-${alert.Severity}`,
clearOnEnter: false,
}
);
});

return <AlertList alerts={report.results} />;
return (
<AlertList
alerts={report.results}
highlight={highlightAlert}
onClick={onAlertClick}
/>
);
}

return (
Expand Down
Loading

0 comments on commit a929d97

Please sign in to comment.