From 9ee293949f9373d9872e08c1b0c86a33700ccdc7 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:42:42 +0000 Subject: [PATCH] feat: plugin config param tooltips --- .cspell.json | 2 +- static/manifest-gui.css | 26 ++++++++++++++++++++++ static/scripts/decode-manifest.ts | 19 ++++++++++++++++ static/types/plugins.ts | 7 ++++-- static/utils/element-helpers.ts | 36 +++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/.cspell.json b/.cspell.json index c9a8062..6ea602e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -8,5 +8,5 @@ "dictionaries": ["typescript", "node", "software-terms"], "import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"], "ignoreRegExpList": ["[0-9a-fA-F]{6}"], - "ignoreWords": ["ubiquibot", "Supabase", "supabase", "SUPABASE", "sonarjs", "mischeck"] + "ignoreWords": ["ubiquibot", "Supabase", "supabase", "SUPABASE", "sonarjs", "mischeck", "tooltiptext"] } diff --git a/static/manifest-gui.css b/static/manifest-gui.css index 01ae511..09bd55f 100644 --- a/static/manifest-gui.css +++ b/static/manifest-gui.css @@ -178,6 +178,32 @@ button#add:active::before { margin: 0 0 16px; } +.tooltip { + position: relative; + display: inline-block; + cursor: help; + padding-left: 8px; +} + +.tooltip .tooltiptext { + visibility: hidden; + width: 200px; + background-color: #101010; + color: #fff; + text-align: center; + border-radius: 4px; + padding: 8px; + position: absolute; + z-index: 1; + opacity: 0; + transition: opacity 0.25s; +} + +.tooltip:hover .tooltiptext { + visibility: visible; + opacity: 1; +} + .picker-select { width: 100%; padding: 8px 16px; diff --git a/static/scripts/decode-manifest.ts b/static/scripts/decode-manifest.ts index 623319e..a951df0 100644 --- a/static/scripts/decode-manifest.ts +++ b/static/scripts/decode-manifest.ts @@ -1,5 +1,22 @@ import { Manifest, ManifestPreDecode } from "../types/plugins"; +function injectDescriptionIntoProperties(properties: ManifestPreDecode["configuration"]["properties"]) { + return Object.fromEntries( + Object.entries(properties).map(([key, value]) => { + const newValue = { + ...value, + description: "This is a placeholder description that'll be replaced once the PRs are merged for the plugins", + }; + + if (value.properties) { + newValue.properties = injectDescriptionIntoProperties(value.properties); + } + + return [key, newValue]; + }) + ); +} + export class ManifestDecoder { constructor() {} @@ -8,6 +25,8 @@ export class ManifestDecoder { return null; } + manifest.configuration.properties = injectDescriptionIntoProperties(manifest.configuration.properties); + const decodedManifest: Manifest = { name: manifest.name, description: manifest.description, diff --git a/static/types/plugins.ts b/static/types/plugins.ts index 3fe14b8..f4e33e3 100644 --- a/static/types/plugins.ts +++ b/static/types/plugins.ts @@ -12,6 +12,7 @@ export interface Uses { } export interface ManifestPreDecode extends Manifest { + manifest: Manifest; actionUrl?: string; workerUrl?: string; error?: string; @@ -34,10 +35,12 @@ export type Manifest = { properties: { [key: string]: { default: unknown; - type?: string; + description?: string; + type: string; + properties?: Record; }; }; }; }; -export type ManifestProps = { type: string; default: string; items?: { type: string }; properties?: Record }; +export type ManifestProps = { type: string; default: unknown; description: string; items?: { type: string }; properties?: Record }; diff --git a/static/utils/element-helpers.ts b/static/utils/element-helpers.ts index dc9116a..691cb5d 100644 --- a/static/utils/element-helpers.ts +++ b/static/utils/element-helpers.ts @@ -27,6 +27,9 @@ export function createInputRow( const headerCell = document.createElement("td"); headerCell.className = "table-data-header"; headerCell.textContent = key; + + createConfigParamTooltip(headerCell, prop); + row.appendChild(headerCell); const valueCell = document.createElement("td"); @@ -106,3 +109,36 @@ export function createTextareaInput(key: string, defaultValue: object | unknown, return inputElem; } + +function createConfigParamTooltip(headerCell: HTMLElement, prop: ManifestProps) { + if (!prop.description) return; + + const tooltip = createElement("span", { class: "tooltip", textContent: "?" }); + const tooltipText = createElement("span", { class: "tooltiptext", textContent: prop.description }); + + tooltip.appendChild(tooltipText); + headerCell.appendChild(tooltip); + + tooltip.addEventListener("mouseenter", () => { + const tooltipRect = tooltip.getBoundingClientRect(); + const tooltipTextRect = tooltipText.getBoundingClientRect(); + const spaceAbove = tooltipRect.top; + const spaceBelow = window.innerHeight - tooltipRect.bottom; + + if (spaceBelow < tooltipTextRect.height && spaceAbove > spaceBelow) { + tooltipText.style.bottom = `${tooltipRect.height}px`; + tooltipText.style.top = "auto"; + } else { + tooltipText.style.top = `${tooltipRect.height}px`; + tooltipText.style.bottom = "auto"; + } + + tooltipText.style.visibility = "visible"; + tooltipText.style.opacity = "1"; + }); + + tooltip.addEventListener("mouseleave", () => { + tooltipText.style.visibility = "hidden"; + tooltipText.style.opacity = "0"; + }); +}