From dadfe7b19d13e383a2b1de5ee57fc9b79459c1ea Mon Sep 17 00:00:00 2001 From: LenAnderson Date: Tue, 23 Apr 2024 18:18:04 -0400 Subject: [PATCH] add autocomplete details tooltips --- .../SlashCommandAutoComplete.js | 3 +- .../SlashCommandAutoCompleteOption.js | 83 ++++++++++++------- public/style.css | 56 ++++++++++--- 3 files changed, 100 insertions(+), 42 deletions(-) diff --git a/public/scripts/slash-commands/SlashCommandAutoComplete.js b/public/scripts/slash-commands/SlashCommandAutoComplete.js index 745cbf87a..0f4a31e10 100644 --- a/public/scripts/slash-commands/SlashCommandAutoComplete.js +++ b/public/scripts/slash-commands/SlashCommandAutoComplete.js @@ -90,7 +90,7 @@ export class SlashCommandAutoComplete { textarea.addEventListener('keydown', (evt)=>this.handleKeyDown(evt)); textarea.addEventListener('click', ()=>this.isActive ? this.show() : null); textarea.addEventListener('selectionchange', ()=>this.show()); - textarea.addEventListener('blur', ()=>this.hide()); + // textarea.addEventListener('blur', ()=>this.hide()); if (isFloating) { textarea.addEventListener('scroll', ()=>this.updateFloatingPositionDebounced()); } @@ -866,6 +866,7 @@ export class SlashCommandAutoComplete { return; } case 'Enter': { + // pick the selected item to autocomplete if (evt.ctrlKey || evt.altKey || evt.shiftKey || this.selectedItem.type == OPTION_TYPE.BLANK) break; if (this.selectedItem.name == this.slashCommand) break; evt.preventDefault(); diff --git a/public/scripts/slash-commands/SlashCommandAutoCompleteOption.js b/public/scripts/slash-commands/SlashCommandAutoCompleteOption.js index 9ee8b0dff..2af019a06 100644 --- a/public/scripts/slash-commands/SlashCommandAutoCompleteOption.js +++ b/public/scripts/slash-commands/SlashCommandAutoCompleteOption.js @@ -120,6 +120,7 @@ export class SlashCommandAutoCompleteOption { const name = document.createElement('div'); { name.classList.add('name'); name.classList.add('monospace'); + name.title = 'command name'; name.textContent = `/${key}`; specs.append(name); } @@ -130,42 +131,58 @@ export class SlashCommandAutoCompleteOption { for (const arg of namedArguments) { const listItem = document.createElement('li'); { listItem.classList.add('argumentItem'); - const argItem = document.createElement('div'); { - argItem.classList.add('argument'); - argItem.classList.add('namedArgument'); - if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional'); - if (arg.acceptsMultiple) argItem.classList.add('multiple'); - const name = document.createElement('span'); { - name.classList.add('argument-name'); - name.textContent = arg.name; - argItem.append(name); - } - if (arg.enumList.length > 0) { - const enums = document.createElement('span'); { - enums.classList.add('argument-enums'); - for (const e of arg.enumList) { - const enumItem = document.createElement('span'); { - enumItem.classList.add('argument-enum'); - enumItem.textContent = e; - enums.append(enumItem); - } - } - argItem.append(enums); + const argSpec = document.createElement('div'); { + argSpec.classList.add('argumentSpec'); + const argItem = document.createElement('div'); { + argItem.classList.add('argument'); + argItem.classList.add('namedArgument'); + argItem.title = `${arg.isRequired ? '' : 'optional '}named argument`; + if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional'); + if (arg.acceptsMultiple) argItem.classList.add('multiple'); + const name = document.createElement('span'); { + name.classList.add('argument-name'); + name.title = `${argItem.title} - name`; + name.textContent = arg.name; + argItem.append(name); } - } else { - const types = document.createElement('span'); { - types.classList.add('argument-types'); - for (const t of arg.typeList) { - const type = document.createElement('span'); { - type.classList.add('argument-type'); - type.textContent = t; - types.append(type); + if (arg.enumList.length > 0) { + const enums = document.createElement('span'); { + enums.classList.add('argument-enums'); + enums.title = `${argItem.title} - accepted values`; + for (const e of arg.enumList) { + const enumItem = document.createElement('span'); { + enumItem.classList.add('argument-enum'); + enumItem.textContent = e; + enums.append(enumItem); + } } + argItem.append(enums); } - argItem.append(types); + } else { + const types = document.createElement('span'); { + types.classList.add('argument-types'); + types.title = `${argItem.title} - accepted types`; + for (const t of arg.typeList) { + const type = document.createElement('span'); { + type.classList.add('argument-type'); + type.textContent = t; + types.append(type); + } + } + argItem.append(types); + } + } + argSpec.append(argItem); + } + if (arg.defaultValue !== null) { + const argDefault = document.createElement('div'); { + argDefault.classList.add('argument-default'); + argDefault.title = 'default value'; + argDefault.textContent = arg.defaultValue.toString(); + argSpec.append(argDefault); } } - listItem.append(argItem); + listItem.append(argSpec); } const desc = document.createElement('div'); { desc.classList.add('argument-description'); @@ -181,11 +198,13 @@ export class SlashCommandAutoCompleteOption { const argItem = document.createElement('div'); { argItem.classList.add('argument'); argItem.classList.add('unnamedArgument'); + argItem.title = `${arg.isRequired ? '' : 'optional '}unnamed argument`; if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional'); if (arg.acceptsMultiple) argItem.classList.add('multiple'); if (arg.enumList.length > 0) { const enums = document.createElement('span'); { enums.classList.add('argument-enums'); + enums.title = `${argItem.title} - accepted values`; for (const e of arg.enumList) { const enumItem = document.createElement('span'); { enumItem.classList.add('argument-enum'); @@ -198,6 +217,7 @@ export class SlashCommandAutoCompleteOption { } else { const types = document.createElement('span'); { types.classList.add('argument-types'); + types.title = `${argItem.title} - accepted types`; for (const t of arg.typeList) { const type = document.createElement('span'); { type.classList.add('argument-type'); @@ -222,6 +242,7 @@ export class SlashCommandAutoCompleteOption { } const returns = document.createElement('span'); { returns.classList.add('returns'); + returns.title = [null, undefined, 'void'].includes(returnType) ? 'command does not return anything' : 'return value'; returns.textContent = returnType ?? 'void'; body.append(returns); } diff --git a/public/style.css b/public/style.css index 5705ae10e..8ecda6551 100644 --- a/public/style.css +++ b/public/style.css @@ -1292,9 +1292,6 @@ select { height: 100%; > .helpContent { &:before { content: "– "; } - /* display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; */ text-overflow: ellipsis; overflow: hidden; font-size: 0.9em;white-space: nowrap; @@ -1314,12 +1311,17 @@ select { flex-direction: column; gap: 0.5em; > .specs { + cursor: default; flex-direction: column; padding: 0.25em 0.25em 0.5em 0.25em; border-bottom: 1px solid var(--ac-color-border); > .name { font-weight: bold; color: var(--ac-color-text); + cursor: help; + &:hover { + text-decoration: 1px dotted underline; + } } > .body { flex-direction: column; @@ -1330,7 +1332,39 @@ select { > .argumentItem::marker { color: color-mix(in srgb, var(--ac-color-text), var(--ac-color-background)); } - .argument.optional + .argument-description:before { + + .argumentSpec { + display: flex; + gap: 0.5em; + .argument-default { + &:before { + content: " = "; + color: var(--ac-color-text); + } + color: var(--ac-color-string); + } + } + + .argument { + cursor: help; + &:hover:not(:has(.argument-name:hover, .argument-types:hover, .argument-enums:hover)) { + text-decoration: 1px dotted underline; + } + } + .argument-name, + .argument-types, + .argument-enums, + .argument-default + { + cursor: help; + &:hover { + text-decoration: 1px dotted underline; + } + } + + .argument.optional + .argument-description:before, + .argumentSpec:has(.argument.optional) + argument.description:before + { content: "(optional) "; color: var(--ac-color-text); opacity: 0.5; @@ -1342,6 +1376,12 @@ select { font-size: 0.9em; } } + .returns { + cursor: help; + &:hover { + text-decoration: 1px dotted underline; + } + } } } > .help { @@ -1418,15 +1458,13 @@ select { color: var(--ac-color-text); } > .argument-types { + color: var(--ac-color-type); word-break: break-all; white-space: break-spaces; > .argument-type + .argument-type:before { content: "|"; color: var(--ac-color-text); }; - > .argument-type { - color: var(--ac-color-type); - } } > .argument-types + .argument-enums, > .argument-name + .argument-enums @@ -1437,15 +1475,13 @@ select { } } > .argument-enums { + color: var(--ac-color-string); word-break: break-all; white-space: break-spaces; > .argument-enum + .argument-enum:before { content: "|"; color: var(--ac-color-text); }; - > .argument-enum { - color: var(--ac-color-string); - } } } }