diff --git a/app/src/constants.ts b/app/src/constants.ts index 232b40a9f..20fb4af35 100644 --- a/app/src/constants.ts +++ b/app/src/constants.ts @@ -82,6 +82,7 @@ export abstract class Constants { public static readonly LOCAL_PDFTHEME = "local-pdftheme"; public static readonly LOCAL_LAYOUTS = "local-layouts"; public static readonly LOCAL_AI = "local-ai"; + public static readonly LOCAL_PLUGINTOPUNPIN = "local-plugintopunpin"; // timeout public static readonly TIMEOUT_DBLCLICK = 190; diff --git a/app/src/layout/topBar.ts b/app/src/layout/topBar.ts index 092cfd00f..ca623e598 100644 --- a/app/src/layout/topBar.ts +++ b/app/src/layout/topBar.ts @@ -102,7 +102,7 @@ export const initBar = (app: App) => { } }; if (!useElement) { - const svgElement = hideElement.querySelector("svg"); + const svgElement = hideElement.querySelector("svg").cloneNode(true) as HTMLElement; svgElement.classList.add("b3-menu__icon"); menuOptions.iconHTML = svgElement.outerHTML; } @@ -275,6 +275,31 @@ const openPlugin = (app: App, target: Element) => { // @ts-ignore const hasSetting = plugin.setting || plugin.__proto__.hasOwnProperty("openSetting"); plugin.topBarIcons.forEach(item => { + const hasUnpin = window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].includes(item.id); + const submenu = [{ + icon: "iconPin", + label: hasUnpin ? window.siyuan.languages.pin : window.siyuan.languages.unpin, + click() { + if (hasUnpin) { + window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].splice(window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].indexOf(item.id), 1); + item.classList.remove("fn__none") + } else { + window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].push(item.id); + window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN] = Array.from(new Set(window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN])); + item.classList.add("fn__none") + } + setStorageVal(Constants.LOCAL_PLUGINTOPUNPIN, window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN]); + } + }]; + if (hasSetting) { + submenu.push({ + icon: "iconSettings", + label: window.siyuan.languages.config, + click() { + plugin.openSetting(); + }, + }) + } const menuOption: IMenu = { icon: "iconInfo", label: item.getAttribute("aria-label"), @@ -282,25 +307,12 @@ const openPlugin = (app: App, target: Element) => { item.dispatchEvent(new CustomEvent("click")) }, type: "submenu", - submenu: [{ - icon: "iconPin", - label: window.siyuan.languages.pin, - click() { - - } - }, { - icon: "iconSettings", - label: window.siyuan.languages.config, - disabled: !hasSetting, - click() { - plugin.openSetting(); - }, - }] + submenu } if (item.querySelector("use")) { menuOption.icon = item.querySelector("use").getAttribute("xlink:href").replace("#", ""); } else { - const svgElement = item.querySelector("svg"); + const svgElement = item.querySelector("svg").cloneNode(true) as HTMLElement; svgElement.classList.add("b3-menu__icon") menuOption.iconHTML = svgElement.outerHTML; } diff --git a/app/src/layout/util.ts b/app/src/layout/util.ts index b93c232a7..8da40a3bb 100644 --- a/app/src/layout/util.ts +++ b/app/src/layout/util.ts @@ -631,6 +631,9 @@ export const resizeTopbar = () => { } else if (left < right && right - left < width / 3) { dragElement.style.paddingLeft = (right - left) + "px"; } + window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].forEach((id: string) => { + toolbarElement.querySelector("#" + id)?.classList.add("fn__none"); + }); }; let resizeTimeout: number; diff --git a/app/src/plugin/index.ts b/app/src/plugin/index.ts index 64bb891ce..e188efd75 100644 --- a/app/src/plugin/index.ts +++ b/app/src/plugin/index.ts @@ -77,7 +77,7 @@ export class Plugin { const iconElement = document.createElement("div"); iconElement.setAttribute("data-menu", "true"); iconElement.addEventListener("click", options.callback); - iconElement.id = "plugin" + genUUID(); + iconElement.id = `plugin_${this.name}_${this.topBarIcons.length}`; if (isMobile()) { iconElement.className = "b3-menu__item"; iconElement.innerHTML = (options.icon.startsWith("icon") ? `` : options.icon) + diff --git a/app/src/plugin/loader.ts b/app/src/plugin/loader.ts index be4dbcb94..e7b7f7b6d 100644 --- a/app/src/plugin/loader.ts +++ b/app/src/plugin/loader.ts @@ -2,10 +2,11 @@ import {fetchSyncPost} from "../util/fetch"; import {App} from "../index"; import {Plugin} from "./index"; /// #if !MOBILE -import {exportLayout} from "../layout/util"; +import {exportLayout, resizeTopbar} from "../layout/util"; /// #endif import {API} from "./API"; import {getFrontend, isMobile, isWindow} from "../util/functions"; +import {Constants} from "../constants"; const getObject = (key: string) => { const api = { @@ -141,9 +142,13 @@ export const afterLoadPlugin = (plugin: Plugin) => { if (isMobile()) { document.querySelector("#menuAbout").after(element); } else if (!isWindow()) { + if (window.siyuan.storage[Constants.LOCAL_PLUGINTOPUNPIN].includes(element.id)) { + element.classList.add("fn__none"); + } document.querySelector("#" + (element.getAttribute("data-position") === "right" ? "barPlugins" : "drag")).before(element); } }); + resizeTopbar(); } /// #if !MOBILE mergePluginHotkey(plugin); diff --git a/app/src/plugin/uninstall.ts b/app/src/plugin/uninstall.ts index 14ac09a10..f745d2bb6 100644 --- a/app/src/plugin/uninstall.ts +++ b/app/src/plugin/uninstall.ts @@ -1,7 +1,7 @@ import {App} from "../index"; import {Plugin} from "../plugin"; import {getAllModels} from "../layout/getAll"; -import {exportLayout} from "../layout/util"; +import {exportLayout, resizeTopbar} from "../layout/util"; import {Constants} from "../constants"; export const uninstall = (app: App, name: string) => { @@ -24,6 +24,7 @@ export const uninstall = (app: App, name: string) => { plugin.topBarIcons.forEach(item => { item.remove(); }); + resizeTopbar(); // rm statusBar /// #if !MOBILE plugin.statusBarIcons.forEach(item => { diff --git a/app/src/protyle/util/compatibility.ts b/app/src/protyle/util/compatibility.ts index 5cff4101a..49be79a4d 100644 --- a/app/src/protyle/util/compatibility.ts +++ b/app/src/protyle/util/compatibility.ts @@ -161,6 +161,7 @@ export const getLocalStorage = (cb: () => void) => { }; defaultStorage[Constants.LOCAL_LAYOUTS] = []; // {name: "", layout:{}} defaultStorage[Constants.LOCAL_AI] = []; // {name: "", memo: ""} + defaultStorage[Constants.LOCAL_PLUGINTOPUNPIN] = []; defaultStorage[Constants.LOCAL_BAZAAR] = { theme: "0", template: "0", @@ -214,7 +215,7 @@ export const getLocalStorage = (cb: () => void) => { [Constants.LOCAL_EXPORTIMG, Constants.LOCAL_SEARCHKEYS, Constants.LOCAL_PDFTHEME, Constants.LOCAL_BAZAAR, Constants.LOCAL_EXPORTWORD, Constants.LOCAL_EXPORTPDF, Constants.LOCAL_DOCINFO, Constants.LOCAL_FONTSTYLES, Constants.LOCAL_SEARCHDATA, - Constants.LOCAL_ZOOM, Constants.LOCAL_LAYOUTS, Constants.LOCAL_AI].forEach((key) => { + Constants.LOCAL_ZOOM, Constants.LOCAL_LAYOUTS, Constants.LOCAL_AI, Constants.LOCAL_PLUGINTOPUNPIN].forEach((key) => { if (typeof response.data[key] === "string") { try { window.siyuan.storage[key] = Object.assign(defaultStorage[key], JSON.parse(response.data[key]));