Skip to content

Commit

Permalink
feat(icon-in-editor): add click menu to change/delete icon
Browse files Browse the repository at this point in the history
when click on icon in editor, a menu will popup showing options to change/delete icon
  • Loading branch information
aidenlx committed Mar 4, 2022
1 parent b3bfdd8 commit 5dc96de
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 41 deletions.
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"conventionalCommits.scopes": [
"browser-packs",
"icon-in-editor"
]
}
47 changes: 6 additions & 41 deletions src/icon-in-editor/deco.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { syntaxTree } from "@codemirror/language";
import { tokenClassNodeProp } from "@codemirror/stream-parser";
import type { EditorView } from "@codemirror/view";
import { Decoration, WidgetType } from "@codemirror/view";
import { Decoration } from "@codemirror/view";
import type { NodeType } from "@lezer/common";
import cls from "classnames";
import { editorLivePreviewField } from "obsidian";

import {
Expand All @@ -12,37 +11,7 @@ import {
stripColons,
} from "../icon-packs/utils";
import type IconSC from "../isc-main";

class IconWidget extends WidgetType {
constructor(public id: string, public plugin: IconSC) {
super();
}

eq(other: IconWidget) {
return other.id === this.id;
}

toDOM() {
const icon = this.plugin.packManager.getIcon(this.id);
let wrap = createSpan({
cls: cls("cm-isc", {
"cm-isc-emoji": typeof icon === "string",
"cm-isc-img": icon instanceof HTMLImageElement,
}),
attr: { "aria-hidden": "true" },
});
if (icon) {
wrap.append(icon);
} else {
wrap.append(`:${this.id}:`);
}
return wrap;
}

ignoreEvent() {
return true;
}
}
import IconWidget from "./widget";

const allowedTypes = [
"link-alias",
Expand Down Expand Up @@ -104,16 +73,12 @@ const icons = (view: EditorView, plugin: IconSC) => {
}
return Decoration.set(
ranges.map(([code, from, to]) => {
const widget = new IconWidget(code, plugin);
widget.setPos(from, to);
if (view.state.field(editorLivePreviewField)) {
return Decoration.replace({
widget: new IconWidget(code, plugin),
side: 1,
}).range(from, to);
return Decoration.replace({ widget, side: 1 }).range(from, to);
} else {
return Decoration.widget({
widget: new IconWidget(code, plugin),
side: 1,
}).range(to);
return Decoration.widget({ widget, side: 1 }).range(to);
}
}),
);
Expand Down
114 changes: 114 additions & 0 deletions src/icon-in-editor/widget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { EditorView, Rect } from "@codemirror/view";
import { WidgetType } from "@codemirror/view";
import cls from "classnames";
import { Menu, Platform } from "obsidian";
import type IconSC from "../isc-main";

abstract class LPWidget extends WidgetType {
start = -1;
end = -1;
menu?: Menu;
setPos(start: number, end: number) {
this.start = start;
this.end = end;
}
hookClickHandler(view: EditorView, el: HTMLElement) {
el.addEventListener("click", (evt) => {
evt.defaultPrevented ||
(this.selectElement(view, el), evt.preventDefault());
});
}
// addEditButton(e, t) {
// var n = this,
// i = t.createDiv("edit-block-button");
// Xy(i, Ov),
// nn(i, "Edit this block"),
// i.addEventListener("click", function () {
// n.selectElement(e, t);
// });
// }
selectElement(view: EditorView, el: HTMLElement) {
let { start, end } = this;
let coord: Rect | null = null;

if (start < 0 || end < 0) {
try {
var pos = view.posAtDOM(el);
view.dispatch({ selection: { head: pos, anchor: pos } });
view.focus();
coord = view.coordsAtPos(pos);
} catch (e) {}
} else {
if (Platform.isMobile) end = start;
try {
view.dispatch({ selection: { head: start, anchor: end } });
view.focus();
coord = view.coordsAtPos(start);
} catch (e) {}
}
if (coord)
this.menu?.showAtPosition({ ...coord, x: coord.left, y: coord.top });
}
// resizeWidget(e, t) {
// XB &&
// new XB(function () {
// return e.requestMeasure();
// }).observe(t, { box: "border-box" });
// }
}
export default class IconWidget extends LPWidget {
constructor(public id: string, public plugin: IconSC) {
super();
}

eq(other: IconWidget) {
return other instanceof IconWidget && other.id === this.id;
}

toDOM(view: EditorView) {
const icon = this.plugin.packManager.getIcon(this.id);
let wrap = createSpan({
cls: cls("cm-isc", {
"cm-isc-emoji": typeof icon === "string",
"cm-isc-img": icon instanceof HTMLImageElement,
}),
// attr: { "aria-hidden": "true" },
});
if (icon) {
wrap.append(icon);
} else {
wrap.append(`:${this.id}:`);
}
this.hookClickHandler(view, wrap);
this.menu = new Menu(this.plugin.app)
.addItem((item) =>
item
.setIcon("image-glyph")
.setTitle("Change Icon")
.onClick(async () => {
const icon = await this.plugin.api.getIconFromUser();
if (!icon) return;
const { start, end } = this;
view.dispatch({
changes: { from: start, to: end, insert: `:${icon.id}:` },
});
}),
)
.addItem((item) =>
item
.setIcon("trash")
.setTitle("Delete Icon")
.onClick(() => {
const { start, end } = this;
view.dispatch({
changes: { from: start, to: end, insert: "" },
});
}),
);
return wrap;
}

ignoreEvent() {
return true;
}
}
8 changes: 8 additions & 0 deletions src/icon-packs/icon.less
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
.view-content .mod-cm6 .cm-isc {
cursor: pointer;
}

img.isc-icon {
display: inline;
height: 1em;
width: 1em;
vertical-align: text-top;
cursor: default;
.view-content .mod-cm6 .cm-isc > & {
cursor: pointer;
}
.markdown-preview-view &,
.markdown-source-view & {
height: var(--editor-font-size);
Expand Down

0 comments on commit 5dc96de

Please sign in to comment.