Hide Commands of other Plugins

This commit is contained in:
phibr0 2022-07-11 12:23:34 +02:00
parent 247f280873
commit f317ead945
19 changed files with 464 additions and 371 deletions

View file

@ -1,7 +1,7 @@
{
"id": "cmdr",
"name": "Commander",
"version": "0.0.8",
"version": "0.0.9",
"minAppVersion": "0.12.0",
"description": "Customize your workspace by adding commands /everywhere/.",
"author": "jsmorabito & phibr0",

612
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "cmdr",
"version": "0.0.8",
"version": "0.0.9",
"description": "Customize your workspace by adding commands /everywhere/.",
"main": "main.js",
"scripts": {

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,14 @@
import { Plugin } from 'obsidian';
import { DEFAULT_SETTINGS } from './constants';
import t from './l10n';
import { EditorMenuCommandManager, FileMenuCommandManager } from './manager/menuManager';
import PageHeaderManager from './manager/pageHeaderManager';
import RibbonManager from './manager/ribbonManager';
import StatusBarManager from './manager/statusBarManager';
import TitleBarManager from './manager/titleBarManager';
import {
EditorMenuCommandManager,
FileMenuCommandManager,
PageHeaderManager,
RibbonManager,
StatusBarManager,
TitleBarManager,
} from "./manager/commands";
import { CommanderSettings, Macro } from './types';
import MacroModal from './ui/macroModal';
import CommanderSettingTab from './ui/settingTab';
@ -13,6 +16,7 @@ import SettingTabModal from './ui/settingTabModal';
import 'beautiful-react-diagrams/styles.css';
import "./styles.scss";
import { updateHiderStylesheet } from './util';
export default class CommanderPlugin extends Plugin {
public settings: CommanderSettings;
@ -60,6 +64,12 @@ export default class CommanderPlugin extends Plugin {
this.registerEvent(
app.workspace.on('file-menu', this.manager.fileMenu.applyFileMenuCommands(this)),
);
updateHiderStylesheet(this.settings);
}
public onunload(): void {
document.head.querySelector("style#cmdr")?.remove();
}
// Macros become quite large objects, because we are saving the whole flowchart state (including position, etc.)

View file

@ -1,7 +1,7 @@
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
export default abstract class CommandManager {
export default abstract class CommandManagerBase {
public pairs: CommandIconPair[];
protected plugin: CommanderPlugin;

View file

@ -0,0 +1,14 @@
import { EditorMenuCommandManager, FileMenuCommandManager } from './menuManager';
import PageHeaderManager from './pageHeaderManager';
import RibbonManager from './ribbonManager';
import StatusBarManager from './statusBarManager';
import TitleBarManager from './titleBarManager';
export {
EditorMenuCommandManager,
FileMenuCommandManager,
PageHeaderManager,
RibbonManager,
StatusBarManager,
TitleBarManager,
};

View file

@ -1,14 +1,14 @@
import { Command, Editor, MarkdownView, Menu, MenuItem, setIcon, TAbstractFile, WorkspaceLeaf } from "obsidian";
import CommandManager from "./_commandManager";
import CommanderPlugin from "../main";
import { CommandIconPair } from "../types";
import ConfirmDeleteModal from "../ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId, isModeActive } from "../util";
import CommandManagerBase from "./commandManager";
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
import ConfirmDeleteModal from "src/ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId, isModeActive } from "src/util";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import t from "src/l10n";
abstract class Base extends CommandManager {
abstract class Base extends CommandManagerBase {
public async addCommand(pair: CommandIconPair): Promise<void> {
this.pairs.push(pair);
await this.plugin.saveSettings();

View file

@ -6,9 +6,9 @@ import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import ConfirmDeleteModal from "src/ui/confirmDeleteModal";
import { chooseNewCommand, isModeActive } from "src/util";
import CommandManager from "./_commandManager";
import CommandManagerBase from "./commandManager";
export default class PageHeaderManager extends CommandManager {
export default class PageHeaderManager extends CommandManagerBase {
private addBtn = createDiv({ cls: "cmdr view-action cmdr-adder", attr: { "aria-label": t("Add new") } });
public constructor(plugin: CommanderPlugin, pairArray: CommandIconPair[]) {
@ -57,7 +57,7 @@ export default class PageHeaderManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle(t("Add Command"))
.setTitle(t("Add command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -142,12 +142,9 @@ export default class PageHeaderManager extends CommandManager {
public reorder(): void | Promise<void> {
const x = document.getElementsByClassName("view-action cmdr-page-header");
const elements: Element[] = [];
for (let i = 0; i < x.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
elements.push(x.item(i)!);
for (let i = x.length - 1; i >= 0; i--) {
x.item(i)?.remove();
}
elements.forEach((e) => e.remove());
}
public async addCommand(pair: CommandIconPair): Promise<void> {
@ -157,13 +154,12 @@ export default class PageHeaderManager extends CommandManager {
public async removeCommand(pair: CommandIconPair): Promise<void> {
this.pairs.remove(pair);
const x = document.getElementsByClassName(`view-action cmdr-page-header ${pair.id}`);
const elements: Element[] = [];
for (let i = 0; i < x.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
elements.push(x.item(i)!);
for (let i = x.length - 1; i >= 0; i--) {
x.item(i)?.remove();
}
elements.forEach((e) => e.remove());
await this.plugin.saveSettings();
}
}

View file

@ -1,15 +1,15 @@
import { isModeActive } from 'src/util';
import { Menu, setIcon, WorkspaceRibbon } from "obsidian";
import CommandManager from "./_commandManager";
import CommanderPlugin from "../main";
import { CommandIconPair } from "../types";
import ConfirmDeleteModal from "../ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId } from "../util";
import CommandManagerBase from "./commandManager";
import CommanderPlugin from "src/main";
import { CommandIconPair } from "src/types";
import ConfirmDeleteModal from "src/ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId } from "src/util";
import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import t from 'src/l10n';
export default class RibbonManager extends CommandManager {
export default class RibbonManager extends CommandManagerBase {
private actions: {
[id: string]: HTMLElement;
};
@ -120,7 +120,7 @@ export default class RibbonManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle(t("Add Command"))
.setTitle(t("Add command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);

View file

@ -6,9 +6,9 @@ import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import ConfirmDeleteModal from "src/ui/confirmDeleteModal";
import { getCommandFromId, chooseNewCommand, isModeActive } from "src/util";
import CommandManager from "./_commandManager";
import CommandManagerBase from "./commandManager";
export default class StatusBarManager extends CommandManager {
export default class StatusBarManager extends CommandManagerBase {
private container: HTMLElement;
private readonly actions = new Map<CommandIconPair, HTMLElement>();
private addBtn = createDiv({ cls: "cmdr status-bar-item cmdr-adder", attr: { "aria-label-position": "top", "aria-label": t("Add new") } });
@ -42,7 +42,7 @@ export default class StatusBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle(t("Add Command"))
.setTitle(t("Add command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);
@ -119,7 +119,7 @@ export default class StatusBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle(t("Add Command"))
.setTitle(t("Add command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);

View file

@ -6,9 +6,9 @@ import ChooseCustomNameModal from "src/ui/chooseCustomNameModal";
import ChooseIconModal from "src/ui/chooseIconModal";
import ConfirmDeleteModal from "src/ui/confirmDeleteModal";
import { chooseNewCommand, getCommandFromId, isModeActive } from "src/util";
import CommandManager from "./_commandManager";
import CommandManagerBase from "./commandManager";
export default class TitleBarManager extends CommandManager {
export default class TitleBarManager extends CommandManagerBase {
private container: HTMLElement;
private readonly actions = new Map<CommandIconPair, HTMLElement>();
private addBtn = createDiv({ cls: "cmdr titlebar-button cmdr-adder", attr: { "aria-label": t("Add new") } });
@ -96,7 +96,7 @@ export default class TitleBarManager extends CommandManager {
new Menu()
.addItem(item => {
item
.setTitle(t("Add Command"))
.setTitle(t("Add command"))
.setIcon("command")
.onClick(async () => {
const pair = await chooseNewCommand(this.plugin);

View file

@ -51,7 +51,6 @@
}
}
.cmdr-setting-content {
overflow-y: auto;
height: calc(100% - 10rem);
}

View file

@ -9,7 +9,11 @@ export interface CommanderSettings {
titleBar: CommandIconPair[];
statusBar: CommandIconPair[];
pageHeader: CommandIconPair[];
macros: Macro[]
macros: Macro[];
hide: {
statusbar: string[];
leftRibbon: string[];
}
}
export interface Macro {

View file

@ -2,7 +2,7 @@ import { createContext, Fragment, h } from "preact";
import CommanderPlugin from "src/main";
import CommandComponent from "./commandComponent";
import logo from "src/assets/commander-logo.svg";
import CommandManager from "src/manager/_commandManager";
import CommandManagerBase from "src/manager/commands/commandManager";
import { chooseNewCommand, isModeActive, ObsidianIcon } from "src/util";
import { arrayMoveMutable } from "array-move";
import ChooseIconModal from "../chooseIconModal";
@ -10,10 +10,10 @@ import ConfirmDeleteModal from "../confirmDeleteModal";
import t from "src/l10n";
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
export const ManagerContext = createContext<CommandManager>(null!);
export const ManagerContext = createContext<CommandManagerBase>(null!);
interface CommandViewerProps {
manager: CommandManager;
manager: CommandManagerBase;
plugin: CommanderPlugin
onOpenHider?: () => void
}

View file

@ -1,21 +1,74 @@
import { PluginManifest } from "obsidian";
import { Fragment, h } from "preact";
import { useMemo } from "preact/hooks";
import { useEffect, useState } from "preact/hooks";
import t from "src/l10n";
import CommanderPlugin from "src/main";
import { updateHiderStylesheet } from "src/util";
import Closable from "./Closable";
import { ToggleComponent } from "./settingComponent";
// eslint-disable-next-line no-unused-vars
export default function HidingViewer({ plugin }: { plugin: CommanderPlugin }): h.JSX.Element {
const tabs = useMemo(() => [
<Closable title={t("Left Ribbon")} index={0}></Closable>,
<Closable title={t("Statusbar")} index={1}></Closable>,
<Closable title={t("Editor Menu")} index={2}></Closable>,
<Closable title={t("File Menu")} index={3}></Closable>,
], []);
return (
<Fragment>
{tabs}
<LeftRibbonHider plugin={plugin} />
<StatusbarHider plugin={plugin} />
</Fragment>
);
}
function LeftRibbonHider({ plugin }: { plugin: CommanderPlugin }): h.JSX.Element {
const [ribbonCommands, setRibbonCommands] = useState<{ name: string, icon: string }[]>([]);
const hiddenCommands = plugin.settings.hide.leftRibbon;
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
setRibbonCommands([...app.workspace.leftRibbon.ribbonActionsEl!.children].filter((el) => !el.hasClass("cmdr")).map((el) => { return { name: el.getAttribute("aria-label")!, icon: el.firstElementChild!.className! }; }));
}, []);
return (
<Closable index={0} title={t("Left Ribbon")}>
{ribbonCommands.map((command) => <ToggleComponent
name={command.name}
description=""
changeHandler={async (value): Promise<void> => {
if (!value) {
hiddenCommands.push(command.name);
} else {
hiddenCommands.contains(command.name) && hiddenCommands.remove(command.name);
}
updateHiderStylesheet(plugin.settings);
await plugin.saveSettings();
}}
value={hiddenCommands.contains(command.name)}
/>)}
</Closable>
);
}
function StatusbarHider({ plugin }: { plugin: CommanderPlugin }): h.JSX.Element {
const hiddenPlugins = plugin.settings.hide.statusbar;
const [pluginsWithRibbonItems, setPluginsWithRibbonItems] = useState<PluginManifest[]>([]);
useEffect(() => {
const statusBarItems = [...app.statusBar.containerEl.getElementsByClassName("status-bar-item")];
const ids = (statusBarItems.map(el => [...el.classList].find((pre) => pre.startsWith("plugin-"))).filter((pre) => pre) as string[]).map((pre) => pre.substring(7));
setPluginsWithRibbonItems(ids.map((id) => app.plugins.manifests[id] || { id, name: id.replace(/-/g, " ").replace(/(^\w{1})|(\s+\w{1})/g, letter => letter.toUpperCase()), description: "Core Plugin" }));
}, []);
return (
<Closable index={1} title={t("Statusbar")}>
{pluginsWithRibbonItems.map((manifest) => <ToggleComponent
name={manifest.name}
description={manifest.description}
value={hiddenPlugins.contains(manifest.id)}
changeHandler={async (value): Promise<void> => {
if (!value) {
hiddenPlugins.push(manifest.id);
} else {
hiddenPlugins.contains(manifest.id) && hiddenPlugins.remove(manifest.id);
}
updateHiderStylesheet(plugin.settings);
await plugin.saveSettings();
}}
/>)}
</Closable>
);
}

View file

@ -58,12 +58,9 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
if (!plugin.settings.showAddCommand) {
const elements = document.getElementsByClassName("cmdr-adder");
const x: Element[] = [];
for (let i = 0; i < elements.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
x.push(elements.item(i)!);
for (let i = elements.length - 1; i >= 0; i--) {
elements.item(i)?.remove();
}
x.forEach((pre) => pre.remove());
} else {
new Notice(t("Please restart Obsidian for these changes to take effect."));
}
@ -82,11 +79,11 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co
},
{
name: t("Editor Menu"),
tab: <CommandViewer manager={plugin.manager.editorMenu} plugin={plugin} onOpenHider={(): void => openHiderTab(2)} />
tab: <CommandViewer manager={plugin.manager.editorMenu} plugin={plugin} />
},
{
name: t("File Menu"),
tab: <CommandViewer manager={plugin.manager.fileMenu} plugin={plugin} onOpenHider={(): void => openHiderTab(3)} />
tab: <CommandViewer manager={plugin.manager.fileMenu} plugin={plugin} />
},
{
name: t("Left Ribbon"),

View file

@ -1,4 +1,4 @@
import { CommandIconPair } from './types';
import { CommanderSettings, CommandIconPair } from './types';
import CommanderPlugin from "./main";
import AddCommandModal from "./ui/addCommandModal";
import ChooseIconModal from './ui/chooseIconModal';
@ -57,3 +57,19 @@ export function isModeActive(mode: string): boolean {
const { isMobile, appId } = app;
return mode === "any" || mode === appId || (mode === "mobile" && isMobile) || (mode === "desktop" && !isMobile);
}
export function updateHiderStylesheet(settings: CommanderSettings): void {
let style = "";
for (const id of settings.hide.statusbar) {
style += `div.status-bar-item.plugin-${id} {display: none; content-visibility: hidden;}`;
}
for (const name of settings.hide.leftRibbon) {
style += `div.side-dock-ribbon-action[aria-label="${name}"] {display: none; content-visibility: hidden;}`;
}
document.head.querySelector("style#cmdr")?.remove();
if (style) {
document.head.appendChild(createEl("style", { attr: { "id": "cmdr" }, text: style, type: "text/css" }));
}
}

View file

@ -11,7 +11,7 @@
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"lib": ["DOM", "ES5", "ES6", "ES7"],
"lib": ["DOM", "ES5", "ES6", "ES7", "DOM.Iterable"],
"jsx": "preserve",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",