summaryrefslogtreecommitdiffstats
path: root/browser/components/sidebar/sidebar-launcher.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/sidebar/sidebar-launcher.mjs')
-rw-r--r--browser/components/sidebar/sidebar-launcher.mjs169
1 files changed, 169 insertions, 0 deletions
diff --git a/browser/components/sidebar/sidebar-launcher.mjs b/browser/components/sidebar/sidebar-launcher.mjs
new file mode 100644
index 0000000000..85eb94b6ca
--- /dev/null
+++ b/browser/components/sidebar/sidebar-launcher.mjs
@@ -0,0 +1,169 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import {
+ html,
+ ifDefined,
+ styleMap,
+} from "chrome://global/content/vendor/lit.all.mjs";
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+
+// eslint-disable-next-line import/no-unassigned-import
+import "chrome://global/content/elements/moz-button.mjs";
+
+/**
+ * Vertical strip attached to the launcher that provides an entry point
+ * to various sidebar panels.
+ *
+ */
+export default class SidebarLauncher extends MozLitElement {
+ static properties = {
+ topActions: { type: Array },
+ bottomActions: { type: Array },
+ selectedView: { type: String },
+ open: { type: Boolean },
+ };
+
+ constructor() {
+ super();
+ this.topActions = [
+ {
+ icon: `url("chrome://browser/skin/insights.svg")`,
+ view: null,
+ l10nId: "sidebar-launcher-insights",
+ },
+ ];
+
+ this.bottomActions = [
+ {
+ l10nId: "sidebar-menu-history",
+ icon: `url("chrome://browser/content/firefoxview/view-history.svg")`,
+ view: "viewHistorySidebar",
+ },
+ {
+ l10nId: "sidebar-menu-bookmarks",
+ icon: `url("chrome://browser/skin/bookmark-hollow.svg")`,
+ view: "viewBookmarksSidebar",
+ },
+ {
+ l10nId: "sidebar-menu-synced-tabs",
+ icon: `url("chrome://browser/skin/device-phone.svg")`,
+ view: "viewTabsSidebar",
+ },
+ ];
+
+ this.selectedView = window.SidebarUI.currentID;
+ this.open = window.SidebarUI.isOpen;
+ this.menuMutationObserver = new MutationObserver(() =>
+ this.#setExtensionItems()
+ );
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._sidebarBox = document.getElementById("sidebar-box");
+ this._sidebarBox.addEventListener("sidebar-show", this);
+ this._sidebarBox.addEventListener("sidebar-hide", this);
+ this._sidebarMenu = document.getElementById("viewSidebarMenu");
+
+ this.menuMutationObserver.observe(this._sidebarMenu, {
+ childList: true,
+ subtree: true,
+ });
+ this.#setExtensionItems();
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this._sidebarBox.removeEventListener("sidebar-show", this);
+ this._sidebarBox.removeEventListener("sidebar-hide", this);
+ this.menuMutationObserver.disconnect();
+ }
+
+ getImageUrl(icon, targetURI) {
+ if (window.IS_STORYBOOK) {
+ return `chrome://global/skin/icons/defaultFavicon.svg`;
+ }
+ if (!icon) {
+ if (targetURI?.startsWith("moz-extension")) {
+ return "chrome://mozapps/skin/extensions/extension.svg";
+ }
+ return `chrome://global/skin/icons/defaultFavicon.svg`;
+ }
+ // If the icon is not for website (doesn't begin with http), we
+ // display it directly. Otherwise we go through the page-icon
+ // protocol to try to get a cached version. We don't load
+ // favicons directly.
+ if (icon.startsWith("http")) {
+ return `page-icon:${targetURI}`;
+ }
+ return icon;
+ }
+
+ #setExtensionItems() {
+ for (let item of this._sidebarMenu.children) {
+ if (item.id.endsWith("-sidebar-action")) {
+ this.topActions.push({
+ tooltiptext: item.label,
+ icon: item.style.getPropertyValue("--webextension-menuitem-image"),
+ view: item.id.slice("menubar_menu_".length),
+ });
+ }
+ }
+ }
+
+ handleEvent(e) {
+ switch (e.type) {
+ case "sidebar-show":
+ this.selectedView = e.detail.viewId;
+ this.open = true;
+ break;
+ case "sidebar-hide":
+ this.open = false;
+ break;
+ }
+ }
+
+ showView(e) {
+ let view = e.target.getAttribute("view");
+ window.SidebarUI.toggle(view);
+ }
+
+ buttonType(action) {
+ return this.open && action.view == this.selectedView
+ ? "icon"
+ : "icon ghost";
+ }
+
+ entrypointTemplate(action) {
+ return html`<moz-button
+ class="icon-button"
+ type=${this.buttonType(action)}
+ view=${action.view}
+ @click=${action.view ? this.showView : null}
+ title=${ifDefined(action.tooltiptext)}
+ data-l10n-id=${ifDefined(action.l10nId)}
+ style=${styleMap({ "--action-icon": action.icon })}
+ >
+ </moz-button>`;
+ }
+
+ render() {
+ return html`
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/sidebar/sidebar-launcher.css"
+ />
+ <div class="wrapper">
+ <div class="top-actions actions-list">
+ ${this.topActions.map(action => this.entrypointTemplate(action))}
+ </div>
+ <div class="bottom-actions actions-list">
+ ${this.bottomActions.map(action => this.entrypointTemplate(action))}
+ </div>
+ </div>
+ `;
+ }
+}
+customElements.define("sidebar-launcher", SidebarLauncher);