From d91fe787e9182c527699e8d057e66da656eea798 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 18:24:22 +0200 Subject: [PATCH 01/11] Replace tribute with text-expander-element for textarea --- package-lock.json | 14 +++++++ package.json | 1 + templates/shared/combomarkdowneditor.tmpl | 4 +- web_src/css/editor-markdown.css | 41 +++++++++++++++++++ .../js/features/comp/ComboMarkdownEditor.js | 40 ++++++++++++++++-- 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9d998a69d2a8..1e03863cc411b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", "@github/markdown-toolbar-element": "2.1.1", + "@github/text-expander-element": "2.3.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "18.3.0", "@vue/compiler-sfc": "3.2.47", @@ -839,11 +840,24 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@github/combobox-nav": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.7.tgz", + "integrity": "sha512-Webx0W5iTpkk5Chy9dB/1BEUORQ0qrwui8HaaVBiy75W2VOJg96WTuKj1rXENAJ3XTMhdEF53bn0LYfvP0EKvg==" + }, "node_modules/@github/markdown-toolbar-element": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.1.1.tgz", "integrity": "sha512-J++rpd5H9baztabJQB82h26jtueOeBRSTqetk9Cri+Lj/s28ndu6Tovn0uHQaOKtBWDobFunk9b5pP5vcqt7cA==" }, + "node_modules/@github/text-expander-element": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@github/text-expander-element/-/text-expander-element-2.3.0.tgz", + "integrity": "sha512-E1KCxTOA/7Y4dP5g7vXbfRDFU6/SjU0TuJxx6JMwvxzI/NlBrXyXsx/fjFskD2T/un6i6CNKnXu1ZwExDLjcqw==", + "dependencies": { + "@github/combobox-nav": "^2.0.2" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", diff --git a/package.json b/package.json index 3ccf0c0840baa..dc4112145288d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", "@github/markdown-toolbar-element": "2.1.1", + "@github/text-expander-element": "2.3.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "18.3.0", "@vue/compiler-sfc": "3.2.47", diff --git a/templates/shared/combomarkdowneditor.tmpl b/templates/shared/combomarkdowneditor.tmpl index 0027ce84271a9..887673e40e0b8 100644 --- a/templates/shared/combomarkdowneditor.tmpl +++ b/templates/shared/combomarkdowneditor.tmpl @@ -39,7 +39,9 @@ Template Attributes: {{svg "octicon-arrow-switch"}} - + + +
{{.locale.Tr "loading"}} diff --git a/web_src/css/editor-markdown.css b/web_src/css/editor-markdown.css index da64164aec3d8..dd04d053d7e5f 100644 --- a/web_src/css/editor-markdown.css +++ b/web_src/css/editor-markdown.css @@ -30,3 +30,44 @@ .combo-markdown-editor .CodeMirror-scroll { max-height: calc(100vh - 200px); } + +text-expander { + display: block; + position: relative; +} + +text-expander .suggestions { + position: absolute; + min-width: 180px; + padding: 0; + margin-top: 24px; + list-style: none; + background: var(--color-box-body); + border-radius: var(--border-radius); + border: 1px solid var(--color-secondary); + box-shadow: 0 .5rem 1rem var(--color-shadow); +} + +text-expander .suggestions li { + display: block; + cursor: pointer; + padding: 4px 8px; + font-weight: 500; +} + +text-expander .suggestions li + li { + border-top: 1px solid var(--color-secondary); +} + +text-expander .suggestions li:first-child { + border-radius: var(--border-radius) var(--border-radius) 0 0; +} + +text-expander .suggestions li:last-child { + border-radius: 0 0 var(--border-radius) var(--border-radius); +} + +text-expander li[aria-selected="true"] { + background: var(--color-primary); + color: var(--color-primary-contrast); +} diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index c1607a1da8716..4bd0fa41ad6bf 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -1,4 +1,5 @@ import '@github/markdown-toolbar-element'; +import '@github/text-expander-element'; import $ from 'jquery'; import {attachTribute} from '../tribute.js'; import {hideElem, showElem, autosize} from '../../utils/dom.js'; @@ -6,6 +7,7 @@ import {initEasyMDEImagePaste, initTextareaImagePaste} from './ImagePaste.js'; import {initMarkupContent} from '../../markup/content.js'; import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js'; import {attachRefIssueContextPopup} from '../contextpopup.js'; +import {emojiKeys, emojiString} from '../emoji.js'; let elementIdCounter = 0; @@ -43,11 +45,9 @@ class ComboMarkdownEditor { this.setupTab(); this.setupDropzone(); - + this.setupExpander(); this.setupTextarea(); - await attachTribute(this.textarea, {mentions: true, emoji: true}); - if (this.userPreferredEditor === 'easymde') { await this.switchToEasyMDE(); } @@ -83,6 +83,40 @@ class ComboMarkdownEditor { } } + setupExpander() { + const expander = this.container.querySelector('text-expander'); + expander?.addEventListener('text-expander-change', ({detail: {key, provide, text}}) => { + if (key === ':') { + const ul = document.createElement('ul'); + ul.classList.add('suggestions'); + + const matches = []; + for (const name of emojiKeys) { + if (name.includes(text)) { + matches.push(name); + if (matches.length > 5) break; + } + } + + for (const name of matches) { + const emoji = emojiString(name); + const li = document.createElement('li'); + li.setAttribute('role', 'option'); + li.setAttribute('data-value', emoji); + li.textContent = `${emoji} :${name}:`; + ul.append(li); + } + + provide(Promise.resolve({matched: true, fragment: ul})); + } + }); + expander?.addEventListener('text-expander-value', ({detail}) => { + if (detail?.key === ':' && detail?.item) { + detail.value = detail.item.getAttribute('data-value'); + } + }); + } + setupDropzone() { const dropzoneParentContainer = this.container.getAttribute('data-dropzone-parent-container'); if (dropzoneParentContainer) { From 9717f9f3e8045c4b2df419e525f007b5e937d6e7 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 19:39:09 +0200 Subject: [PATCH 02/11] remove colons --- web_src/js/features/comp/ComboMarkdownEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index 4bd0fa41ad6bf..5660ddcfa07e0 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -103,7 +103,7 @@ class ComboMarkdownEditor { const li = document.createElement('li'); li.setAttribute('role', 'option'); li.setAttribute('data-value', emoji); - li.textContent = `${emoji} :${name}:`; + li.textContent = `${emoji} ${name}`; ul.append(li); } From c8f053261b0fb6858d25770735bad7880e5e7cbf Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 19:44:06 +0200 Subject: [PATCH 03/11] border tweaks --- web_src/css/editor-markdown.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web_src/css/editor-markdown.css b/web_src/css/editor-markdown.css index dd04d053d7e5f..d596128b7c974 100644 --- a/web_src/css/editor-markdown.css +++ b/web_src/css/editor-markdown.css @@ -43,7 +43,7 @@ text-expander .suggestions { margin-top: 24px; list-style: none; background: var(--color-box-body); - border-radius: var(--border-radius); + border-radius: 5px; border: 1px solid var(--color-secondary); box-shadow: 0 .5rem 1rem var(--color-shadow); } @@ -56,15 +56,15 @@ text-expander .suggestions li { } text-expander .suggestions li + li { - border-top: 1px solid var(--color-secondary); + border-top: 1px solid var(--color-secondary-alpha-40); } text-expander .suggestions li:first-child { - border-radius: var(--border-radius) var(--border-radius) 0 0; + border-radius: 4px 4px 0 0; } text-expander .suggestions li:last-child { - border-radius: 0 0 var(--border-radius) var(--border-radius); + border-radius: 0 0 4px 4px; } text-expander li[aria-selected="true"] { From fddfaf0652d7972c8d28340527ab78b3fa733ac6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 19:46:08 +0200 Subject: [PATCH 04/11] move init --- web_src/js/features/comp/ComboMarkdownEditor.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index 5660ddcfa07e0..abacc9ad9e65d 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -42,11 +42,10 @@ class ComboMarkdownEditor { async init() { this.prepareEasyMDEToolbarActions(); - this.setupTab(); this.setupDropzone(); - this.setupExpander(); this.setupTextarea(); + this.setupExpander(); if (this.userPreferredEditor === 'easymde') { await this.switchToEasyMDE(); From b64f44f09d0ea17e9faef0bb801062eb82dd431b Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 20:29:43 +0200 Subject: [PATCH 05/11] Update web_src/js/features/comp/ComboMarkdownEditor.js --- web_src/js/features/comp/ComboMarkdownEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index abacc9ad9e65d..142eb25f58f22 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -93,7 +93,7 @@ class ComboMarkdownEditor { for (const name of emojiKeys) { if (name.includes(text)) { matches.push(name); - if (matches.length > 5) break; + if (matches.length > 4) break; } } From 0e1137c6fc4b1dbd3cf823ea113780827b3d8f99 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 22:12:47 +0200 Subject: [PATCH 06/11] add hover --- web_src/css/editor-markdown.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web_src/css/editor-markdown.css b/web_src/css/editor-markdown.css index d596128b7c974..737ee29465008 100644 --- a/web_src/css/editor-markdown.css +++ b/web_src/css/editor-markdown.css @@ -67,6 +67,10 @@ text-expander .suggestions li:last-child { border-radius: 0 0 4px 4px; } +text-expander li:hover { + background: var(--color-hover); +} + text-expander li[aria-selected="true"] { background: var(--color-primary); color: var(--color-primary-contrast); From 60ef1bb3ef194086e7bc67b3c4bfde2df950d1a6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 22:17:42 +0200 Subject: [PATCH 07/11] remove unneeded promise wrapper --- web_src/js/features/comp/ComboMarkdownEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index 142eb25f58f22..7275ce683893d 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -106,7 +106,7 @@ class ComboMarkdownEditor { ul.append(li); } - provide(Promise.resolve({matched: true, fragment: ul})); + provide({matched: matches.length > 0, fragment: ul}); } }); expander?.addEventListener('text-expander-value', ({detail}) => { From 037201b9c574dba7005cb74093f52738ac440fb8 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 22:20:55 +0200 Subject: [PATCH 08/11] disable fomantic color transition on textarea --- web_src/css/form.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web_src/css/form.css b/web_src/css/form.css index ffcf5794b9a2c..17948f96bd72c 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -1,3 +1,8 @@ +.ui.input textarea, +.ui.form textarea { + transition: none; +} + input, textarea, .ui.input > input, From 57f1773aeb526ab3cba1bb8626836bb813911485 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 22:23:57 +0200 Subject: [PATCH 09/11] disable transition on input too --- web_src/css/form.css | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/web_src/css/form.css b/web_src/css/form.css index 17948f96bd72c..85d1136de8149 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -1,5 +1,17 @@ .ui.input textarea, -.ui.form textarea { +.ui.form textarea, +.ui.form input:not([type]), +.ui.form input[type="date"], +.ui.form input[type="datetime-local"], +.ui.form input[type="email"], +.ui.form input[type="number"], +.ui.form input[type="password"], +.ui.form input[type="search"], +.ui.form input[type="tel"], +.ui.form input[type="time"], +.ui.form input[type="text"], +.ui.form input[type="file"], +.ui.form input[type="url"] { transition: none; } From b64ddd47ca3b31919c56514b8848929e21c64e78 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 7 Apr 2023 23:16:48 +0200 Subject: [PATCH 10/11] implement mentions --- web_src/css/editor-markdown.css | 20 ++++++-- .../js/features/comp/ComboMarkdownEditor.js | 49 ++++++++++++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/web_src/css/editor-markdown.css b/web_src/css/editor-markdown.css index 737ee29465008..2627a6d73c019 100644 --- a/web_src/css/editor-markdown.css +++ b/web_src/css/editor-markdown.css @@ -49,7 +49,8 @@ text-expander .suggestions { } text-expander .suggestions li { - display: block; + display: flex; + align-items: center; cursor: pointer; padding: 4px 8px; font-weight: 500; @@ -67,11 +68,24 @@ text-expander .suggestions li:last-child { border-radius: 0 0 4px 4px; } -text-expander li:hover { +text-expander .suggestions li:hover { background: var(--color-hover); } -text-expander li[aria-selected="true"] { +text-expander .suggestions .fullname { + font-weight: normal; + margin-left: 4px; + color: var(--color-text-light-1); +} + +text-expander .suggestions li[aria-selected="true"], +text-expander .suggestions li[aria-selected="true"] span { background: var(--color-primary); color: var(--color-primary-contrast); } + +text-expander .suggestions img { + width: 24px; + height: 24px; + margin-right: 8px; +} diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index 7275ce683893d..13b28da828d05 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -10,6 +10,7 @@ import {attachRefIssueContextPopup} from '../contextpopup.js'; import {emojiKeys, emojiString} from '../emoji.js'; let elementIdCounter = 0; +const maxExpanderMatches = 6; /** * validate if the given textarea is non-empty. @@ -86,17 +87,17 @@ class ComboMarkdownEditor { const expander = this.container.querySelector('text-expander'); expander?.addEventListener('text-expander-change', ({detail: {key, provide, text}}) => { if (key === ':') { - const ul = document.createElement('ul'); - ul.classList.add('suggestions'); - const matches = []; for (const name of emojiKeys) { if (name.includes(text)) { matches.push(name); - if (matches.length > 4) break; + if (matches.length >= maxExpanderMatches) break; } } + if (!matches.length) return provide({matched: false}); + const ul = document.createElement('ul'); + ul.classList.add('suggestions'); for (const name of matches) { const emoji = emojiString(name); const li = document.createElement('li'); @@ -106,11 +107,47 @@ class ComboMarkdownEditor { ul.append(li); } - provide({matched: matches.length > 0, fragment: ul}); + provide({matched: true, fragment: ul}); + } else if (key === '@') { + const matches = []; + for (const obj of window.config.tributeValues) { + if (obj.key.includes(text)) { + matches.push(obj); + if (matches.length >= maxExpanderMatches) break; + } + } + if (!matches.length) return provide({matched: false}); + + const ul = document.createElement('ul'); + ul.classList.add('suggestions'); + for (const {value, name, fullname, avatar} of matches) { + const li = document.createElement('li'); + li.setAttribute('role', 'option'); + li.setAttribute('data-value', `${key}${value}`); + + const img = document.createElement('img'); + img.src = avatar; + li.append(img); + + const nameSpan = document.createElement('span'); + nameSpan.textContent = name; + li.append(nameSpan); + + if (fullname && fullname.toLowerCase() !== name) { + const fullnameSpan = document.createElement('span'); + fullnameSpan.classList.add('fullname'); + fullnameSpan.textContent = fullname; + li.append(fullnameSpan); + } + + ul.append(li); + } + + provide({matched: true, fragment: ul}); } }); expander?.addEventListener('text-expander-value', ({detail}) => { - if (detail?.key === ':' && detail?.item) { + if (detail?.item) { detail.value = detail.item.getAttribute('data-value'); } }); From b06f27bd3ef174d996f67ab7c1868f650a8e1613 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 8 Apr 2023 00:32:45 +0200 Subject: [PATCH 11/11] fix border-radius with single child --- web_src/css/editor-markdown.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web_src/css/editor-markdown.css b/web_src/css/editor-markdown.css index 2627a6d73c019..1a09b5d59670a 100644 --- a/web_src/css/editor-markdown.css +++ b/web_src/css/editor-markdown.css @@ -68,6 +68,10 @@ text-expander .suggestions li:last-child { border-radius: 0 0 4px 4px; } +text-expander .suggestions li:only-child { + border-radius: 4px; +} + text-expander .suggestions li:hover { background: var(--color-hover); }