diff --git a/.editorconfig b/.editorconfig index 885c8f7a2..2df3d0518 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,6 +19,11 @@ indent_size = 4 indent_style = space indent_size = 2 +[*.{ts,tsx}] +indent_style = space +indent_size = 4 +quote_type = single + # Dotnet code style settings: [*.{cs,vb}] trim_trailing_whitespace=true diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 434315bb7..a49192f40 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -59,6 +59,9 @@ jobs: - name: Lint run: npm run lint + - name: Format + run: npm run fmt:check + build: runs-on: ${{ matrix.os }} diff --git a/src/Elastic.Markdown/.prettierignore b/src/Elastic.Markdown/.prettierignore new file mode 100644 index 000000000..1b8ac8894 --- /dev/null +++ b/src/Elastic.Markdown/.prettierignore @@ -0,0 +1,3 @@ +# Ignore artifacts: +build +coverage diff --git a/src/Elastic.Markdown/.prettierrc b/src/Elastic.Markdown/.prettierrc new file mode 100644 index 000000000..7fe98d909 --- /dev/null +++ b/src/Elastic.Markdown/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "trailingComma": "es5", + "singleQuote": true, + "plugins": ["prettier-plugin-tailwindcss"] +} diff --git a/src/Elastic.Markdown/Assets/copybutton.css b/src/Elastic.Markdown/Assets/copybutton.css index 4b50379d6..2a1f5d668 100644 --- a/src/Elastic.Markdown/Assets/copybutton.css +++ b/src/Elastic.Markdown/Assets/copybutton.css @@ -1,41 +1,45 @@ /* Copy buttons */ button.copybtn { - position: absolute; - display: flex; - top: calc(var(--spacing) * 5); - right: calc(var(--spacing) * 4); - width: 1.7em; - height: 1.7em; + position: absolute; + display: flex; + top: calc(var(--spacing) * 5); + right: calc(var(--spacing) * 4); + width: 1.7em; + height: 1.7em; opacity: 0; - transition: opacity 0.3s, border .3s, background-color .3s; - user-select: none; + transition: + opacity 0.3s, + border 0.3s, + background-color 0.3s; + user-select: none; cursor: pointer; - padding: 0; - border: none; - outline: none; - border-radius: 0.4em; - background-color: rgb(34, 39, 46); - color: var(--color-grey-50); + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + background-color: rgb(34, 39, 46); + color: var(--color-grey-50); } button.copybtn.success { background-color: rgb(34, 39, 46); - color: #22863a; + color: #22863a; } button.copybtn svg { - stroke: currentColor; - width: 1.5em; - height: 1.5em; - padding: 0.1em; + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; } -div.highlight { - position: relative; +div.highlight { + position: relative; } /* Show the copybutton */ -.highlight:hover button.copybtn, button.copybtn.success { +.highlight:hover button.copybtn, +button.copybtn.success { opacity: 1; } @@ -47,39 +51,43 @@ div.highlight { * *

Short

*/ - .o-tooltip--left { - position: relative; - } +.o-tooltip--left { + position: relative; +} - .o-tooltip--left:after { - opacity: 0; - visibility: hidden; - position: absolute; - content: attr(data-tooltip); - padding: .2em; - font-size: var(--text-sm); - left: -.2em; +.o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: 0.2em; + font-size: var(--text-sm); + left: -0.2em; background-color: rgb(34, 39, 46); - color: var(--color-grey-50); - white-space: nowrap; - z-index: 2; - border-radius: 2px; - transform: translateX(-102%) translateY(0); - transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + color: var(--color-grey-50); + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: + opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), + transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); } .o-tooltip--left:hover:after { - display: block; - opacity: 1; - visibility: visible; - transform: translateX(-100%) translateY(0); - transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); - transition-delay: .5s; + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: + opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), + transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: 0.5s; } /* By default the copy button shouldn't show up when printing a page */ @media print { - button.copybtn { - display: none; - } + button.copybtn { + display: none; + } } diff --git a/src/Elastic.Markdown/Assets/copybutton.ts b/src/Elastic.Markdown/Assets/copybutton.ts index 89718e26c..946c7fd8b 100644 --- a/src/Elastic.Markdown/Assets/copybutton.ts +++ b/src/Elastic.Markdown/Assets/copybutton.ts @@ -3,73 +3,76 @@ import * as ClipboardJS from 'clipboard' const DOCUMENTATION_OPTIONS = { - VERSION: '', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +} const messages = { - 'en': { - 'copy': 'Copy', - 'copy_to_clipboard': 'Copy to clipboard', - 'copy_success': 'Copied!', - 'copy_failure': 'Failed to copy', - }, - 'es' : { - 'copy': 'Copiar', - 'copy_to_clipboard': 'Copiar al portapapeles', - 'copy_success': '¡Copiado!', - 'copy_failure': 'Error al copiar', - }, - 'de' : { - 'copy': 'Kopieren', - 'copy_to_clipboard': 'In die Zwischenablage kopieren', - 'copy_success': 'Kopiert!', - 'copy_failure': 'Fehler beim Kopieren', - }, - 'fr' : { - 'copy': 'Copier', - 'copy_to_clipboard': 'Copier dans le presse-papier', - 'copy_success': 'Copié !', - 'copy_failure': 'Échec de la copie', - }, - 'ru': { - 'copy': 'Скопировать', - 'copy_to_clipboard': 'Скопировать в буфер', - 'copy_success': 'Скопировано!', - 'copy_failure': 'Не удалось скопировать', - }, - 'zh-CN': { - 'copy': '复制', - 'copy_to_clipboard': '复制到剪贴板', - 'copy_success': '复制成功!', - 'copy_failure': '复制失败', - }, - 'it' : { - 'copy': 'Copiare', - 'copy_to_clipboard': 'Copiato negli appunti', - 'copy_success': 'Copiato!', - 'copy_failure': 'Errore durante la copia', - } + en: { + copy: 'Copy', + copy_to_clipboard: 'Copy to clipboard', + copy_success: 'Copied!', + copy_failure: 'Failed to copy', + }, + es: { + copy: 'Copiar', + copy_to_clipboard: 'Copiar al portapapeles', + copy_success: '¡Copiado!', + copy_failure: 'Error al copiar', + }, + de: { + copy: 'Kopieren', + copy_to_clipboard: 'In die Zwischenablage kopieren', + copy_success: 'Kopiert!', + copy_failure: 'Fehler beim Kopieren', + }, + fr: { + copy: 'Copier', + copy_to_clipboard: 'Copier dans le presse-papier', + copy_success: 'Copié !', + copy_failure: 'Échec de la copie', + }, + ru: { + copy: 'Скопировать', + copy_to_clipboard: 'Скопировать в буфер', + copy_success: 'Скопировано!', + copy_failure: 'Не удалось скопировать', + }, + 'zh-CN': { + copy: '复制', + copy_to_clipboard: '复制到剪贴板', + copy_success: '复制成功!', + copy_failure: '复制失败', + }, + it: { + copy: 'Copiare', + copy_to_clipboard: 'Copiato negli appunti', + copy_success: 'Copiato!', + copy_failure: 'Errore durante la copia', + }, } -const locale = 'en' -if( document.documentElement.lang !== undefined - && messages[document.documentElement.lang] !== undefined ) { - locale = document.documentElement.lang +let locale = 'en' +if ( + document.documentElement.lang !== undefined && + messages[document.documentElement.lang] !== undefined +) { + locale = document.documentElement.lang } -const doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +let doc_url_root = + 'URL_ROOT' in DOCUMENTATION_OPTIONS ? DOCUMENTATION_OPTIONS.URL_ROOT : '' if (doc_url_root == '#') { - doc_url_root = ''; + doc_url_root = '' } /** @@ -82,12 +85,12 @@ const iconCheck = ` +let iconCopy = ` -`; +` if (!iconCopy) { - iconCopy = ` + iconCopy = ` ${messages[locale]['copy_to_clipboard']} @@ -95,150 +98,172 @@ if (!iconCopy) { ` } -const codeCellId = index => `codecell${index}` +const codeCellId = (index) => `codecell${index}` // Clears selected text since ClipboardJS will select the text when copying const clearSelection = () => { - if (window.getSelection) { - window.getSelection().removeAllRanges() - } else if (document.selection) { - document.selection.empty() - } + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if ('selection' in document) { + ;(document.selection as Selection).empty() + } } // Changes tooltip text for a moment, then changes it back // We want the timeout of our `success` class to be a bit shorter than the // tooltip and icon change, so that we can hide the icon before changing back. -const timeoutIcon = 1500; -const timeoutSuccessClass = 1500; +const timeoutIcon = 1500 +const timeoutSuccessClass = 1500 const temporarilyChangeTooltip = (el, oldText, newText) => { - el.setAttribute('data-tooltip', newText) - el.classList.add('success') - // Remove success a little bit sooner than we change the tooltip - // So that we can use CSS to hide the copybutton first - setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) - setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) } // Changes the copy button icon for two seconds, then changes it back const temporarilyChangeIcon = (el) => { - el.innerHTML = iconCheck; - setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) + el.innerHTML = iconCheck + setTimeout(() => { + el.innerHTML = iconCopy + }, timeoutIcon) } const addCopyButtonToCodeCells = () => { - // If ClipboardJS hasn't loaded, wait a bit and try again. This - // happens because we load ClipboardJS asynchronously. - - // Add copybuttons to all of our code cells - const COPYBUTTON_SELECTOR = '.highlight pre'; - const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) - codeCells.forEach((codeCell, index) => { - if (codeCell.id) { - return - } - - const id = codeCellId(index) - codeCell.setAttribute('id', id) - - const clipboardButton = id => - `