From c74dbeeb04b73b8618c07d486f1d269ecb9e7cba Mon Sep 17 00:00:00 2001 From: PierreDemailly Date: Wed, 29 Nov 2023 22:21:57 +0100 Subject: [PATCH] feat: create new header menu --- public/css/components/package/header.css | 32 +++++++++++ public/css/style.css | 2 +- public/img/arrow-right-solid.svg | 1 + public/js/components/package/header.js | 70 ++++++++++++++---------- public/js/utils.js | 15 +++++ views/index.html | 1 + 6 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 public/img/arrow-right-solid.svg diff --git a/public/css/components/package/header.css b/public/css/components/package/header.css index dc6f66d0..3adbbf6b 100644 --- a/public/css/components/package/header.css +++ b/public/css/components/package/header.css @@ -26,6 +26,38 @@ div.package-head-information>.package-name>.version { display: flex; align-items: end; } +div.package-head-information>.package-name>.info { + background: url("../../../img/arrow-right-solid.svg"); + background-position: center center; + background-repeat: no-repeat; + width: 18px; + height: 22px; + border: none; + margin-left: auto; + cursor: pointer; + /* https://codepen.io/sosuke/pen/Pjoqqp */ + filter: invert(71%) sepia(22%) saturate(6942%) hue-rotate(149deg) brightness(101%) contrast(106%); +} +div.package-head-information>.package-name>.info-menu { + background: #f7f7f7; + padding: 16px; + border: none; + border-radius: 6px; + position: absolute; + left: 420px; + width: 160px; + text-shadow: none; +} +div.package-head-information>.package-name>.info-menu>.info-menu-title { + font-weight: bold; + text-align: center; + margin-bottom: 12px; + color: rgb(39, 38, 38); +} +div.package-head-information>.package-name>.info-menu>a { + display: block; + margin-bottom: 4px; +} div.package-head-information>ul.package-flags { display: flex; diff --git a/public/css/style.css b/public/css/style.css index 5b7da37e..512aed31 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -82,6 +82,6 @@ main { left: 0; top: 0; } - main > section.content .view.hidden { + main .hidden { display: none; } diff --git a/public/img/arrow-right-solid.svg b/public/img/arrow-right-solid.svg new file mode 100644 index 00000000..edb2e715 --- /dev/null +++ b/public/img/arrow-right-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/js/components/package/header.js b/public/js/components/package/header.js index 062ad79f..d1c78b09 100644 --- a/public/js/components/package/header.js +++ b/public/js/components/package/header.js @@ -28,9 +28,10 @@ export class PackageHeader { flags } = this.package.dependencyVersion; - const [nameDomElement, versionDomElement, descriptionDomElement, linksDomElement, flagsDomElement] = [ + const [nameDomElement, versionDomElement, menuDomElement, descriptionDomElement, linksDomElement, flagsDomElement] = [ clone.querySelector(".name"), clone.querySelector(".version"), + clone.querySelector(".info"), clone.querySelector(".package-description"), clone.querySelector(".package-links"), clone.querySelector(".package-flags") @@ -43,6 +44,20 @@ export class PackageHeader { } versionDomElement.textContent = `v${packageVersion}`; + // Menu + const menu = this.renderMenu(packageName); + menuDomElement.insertAdjacentElement("afterend", menu); + menuDomElement.addEventListener("click", () => { + const menu = menuDomElement.parentNode.querySelector(".info-menu"); + if (menu.classList.contains("hidden")) { + menu.classList.remove("hidden"); + } + else { + menu.classList.add("hidden"); + } + utils.hideOnClickOutside(menu, [menuDomElement]); + }); + // Description const description = packageDescription.trim(); if (description === "") { @@ -89,12 +104,6 @@ export class PackageHeader { icon: "icon-vcard", showInHeader: true }, - thirdParty: { - menu: this.renderToolsMenu(packageName), - text: 'Tools', - icon: 'icon-link', - showInHeader: true - } }; linksDomElement.appendChild(this.renderLinks(links)); @@ -159,31 +168,32 @@ export class PackageHeader { * @param {!string} packageName * @returns {HTMLElement[]} */ - renderToolsMenu(packageName) { + renderMenu(packageName) { const { snykAdvisor, socket } = PackageHeader.ExternalLinks; - return [ - utils.createDOMElement('span', { text: 'Tools' }), - utils.createDOMElement('div', { - classList: ['tools-menu'], - childs: [ - utils.createDOMElement('a', { - text: 'Snyk', - attributes: { - href: snykAdvisor + packageName, - target: "_blank", - } - }), - utils.createDOMElement('a', { - text: 'Socket.dev', - attributes: { - href: socket + packageName, - target: "_blank", - } - }) - ] - }) - ] + return utils.createDOMElement('div', { + classList: ['info-menu', 'hidden'], + childs: [ + utils.createDOMElement("div", { + text: "Third-party tools", + classList: ['info-menu-title'], + }), + utils.createDOMElement('a', { + text: 'Snyk', + attributes: { + href: snykAdvisor + packageName, + target: "_blank", + } + }), + utils.createDOMElement('a', { + text: 'Socket.dev', + attributes: { + href: socket + packageName, + target: "_blank", + } + }) + ] + }); } renderFlags(flags) { diff --git a/public/js/utils.js b/public/js/utils.js index 933720d9..5465c700 100644 --- a/public/js/utils.js +++ b/public/js/utils.js @@ -322,3 +322,18 @@ export function copyToClipboard(str) { document.getSelection().addRange(selected); // Restore the original selection } }; + +export function hideOnClickOutside(element, blacklistElements = []) { + const outsideClickListener = (event) => { + if (!element.contains(event.target) && !blacklistElements.includes(event.target)) { + element.classList.add("hidden"); + removeClickListener(); + } + } + + const removeClickListener = () => { + document.removeEventListener('click', outsideClickListener); + } + + document.addEventListener('click', outsideClickListener); +} diff --git a/views/index.html b/views/index.html index 74cba9ad..6aafe4d7 100644 --- a/views/index.html +++ b/views/index.html @@ -267,6 +267,7 @@

General

+