From acf27299e4bcee90f3f9118ca818898178a4a03d Mon Sep 17 00:00:00 2001 From: Robert Baruck Date: Thu, 26 Sep 2024 10:00:04 +0200 Subject: [PATCH] TASK: Clean up, fix issues --- .../Integration/Controller/Backend/New.fusion | 24 ++-- .../Pages/SetupSecondFactorPage.fusion | 27 +++- Resources/Public/Styles/Login.css | 31 +++- Resources/Public/index.js | 134 ++++++++++-------- 4 files changed, 135 insertions(+), 81 deletions(-) diff --git a/Resources/Private/Fusion/Integration/Controller/Backend/New.fusion b/Resources/Private/Fusion/Integration/Controller/Backend/New.fusion index 6bf08a2..16ed82a 100644 --- a/Resources/Private/Fusion/Integration/Controller/Backend/New.fusion +++ b/Resources/Private/Fusion/Integration/Controller/Backend/New.fusion @@ -36,21 +36,17 @@ Sandstorm.NeosTwoFactorAuthentication.BackendController.new = Sandstorm.NeosTwoF }

-
- - - - - - + -
- - - - - - +
diff --git a/Resources/Private/Fusion/Presentation/Pages/SetupSecondFactorPage.fusion b/Resources/Private/Fusion/Presentation/Pages/SetupSecondFactorPage.fusion index 72f877f..33f7c09 100644 --- a/Resources/Private/Fusion/Presentation/Pages/SetupSecondFactorPage.fusion +++ b/Resources/Private/Fusion/Presentation/Pages/SetupSecondFactorPage.fusion @@ -105,21 +105,36 @@ prototype(Sandstorm.NeosTwoFactorAuthentication:Page.SetupSecondFactorPage) < pr }

-
- + -
- +
diff --git a/Resources/Public/Styles/Login.css b/Resources/Public/Styles/Login.css index bf9034a..28d9b6f 100644 --- a/Resources/Public/Styles/Login.css +++ b/Resources/Public/Styles/Login.css @@ -16,6 +16,7 @@ } .neos-two-factor__secret-wrapper { + /* specificity hack */ display: flex !important; } @@ -46,12 +47,19 @@ } .neos-two-factor__secret__copy__button { + /* specificity hack */ display: flex !important; gap: 8px; align-items: center; justify-content: center; } +.neos-two-factor__secret__copy__button span, +.neos-two-factor__secret__copy__button span i { + display: flex; + align-items: center; +} + .neos-two-factor__secret__copy__button svg { height: 16px; width: 16px; @@ -61,6 +69,7 @@ } .neos-two-factor__hidden { + /* specificity hack */ display: none !important; } @@ -69,6 +78,17 @@ display: block; width: 100%; overflow: hidden; + + font-size: 14px; + line-height: 1.6em; +} + +.neos-two-factor__secret div, +.neos-two-factor__secret p, +.neos-two-factor__secret svg { + box-sizing: content-box; + margin: 0 !important; + padding: 0 !important; } .neos-two-factor__secret p { @@ -76,7 +96,10 @@ color: #0f0f0f; font-family: monospace; - letter-spacing: 2px; +} + +.neos-two-factor__secret span:nth-child(3n) { + margin-right: 4px; } .neos-two-factor__secret .neos-two-factor__secret__number { @@ -88,7 +111,7 @@ position: absolute; top: 0; width: 10em; - height: 100%; + height: 1.6em; display: flex; align-items: center; @@ -98,9 +121,9 @@ .neos-two-factor__secret__overflow-indicator--left svg, .neos-two-factor__secret__overflow-indicator--right svg { - height: 18px; + height: 1.2em; - fill: #1a1a1a; + fill: #3f3f3f; } .neos-two-factor__secret__overflow-indicator--left { diff --git a/Resources/Public/index.js b/Resources/Public/index.js index 646cccb..4d1d930 100644 --- a/Resources/Public/index.js +++ b/Resources/Public/index.js @@ -1,63 +1,83 @@ +// Progressively enhance the secret form element on load window.addEventListener('load', function () { document.querySelectorAll('.neos-two-factor__secret-wrapper') - .forEach(function (secretFormElement) { - const secretInput = secretFormElement.querySelector('input#secret') - const secretDialog = secretFormElement.querySelector('dialog') - const showSecretButton = secretFormElement.querySelector('.neos-two-factor__secret__show__button') - const secretDialogCloseButton = secretDialog.querySelector('.neos-two-factor__secret__close__button') - - showSecretButton.onclick = function () { - secretDialog.showModal() - } - - secretDialogCloseButton.onclick = function () { - secretDialog.close() - } - - const secretDisplay = secretDialog.querySelector('.neos-two-factor__secret') - const allChars = Array.from(secretDisplay.querySelectorAll('span')) - const firstChar = allChars[0] - const lastChar = allChars[allChars.length - 1] - const overflowIndicatorLeft = secretDialog.querySelector('.neos-two-factor__secret__overflow-indicator--left') - const overflowIndicatorRight = secretDialog.querySelector('.neos-two-factor__secret__overflow-indicator--right') - - const intersectionObserverFirstChar = new IntersectionObserver(function (entries) { - if (entries[0].isIntersecting) { - overflowIndicatorLeft.classList.add('neos-two-factor__hidden') - } else { - overflowIndicatorLeft.classList.remove('neos-two-factor__hidden') - } + .forEach(progressivelyEnhanceSecretFormElement) +}) + +function progressivelyEnhanceSecretFormElement(secretFormElement) { + // Collect inner elements (scoped to the secretFormElement) + const secretInput = secretFormElement.querySelector('input#secret') + const secretDialog = secretFormElement.querySelector('dialog') + const showSecretButton = secretFormElement.querySelector('.neos-two-factor__secret__show__button') + const secretDialogCloseButton = secretDialog.querySelector('.neos-two-factor__secret__close__button') + const secretDisplay = secretDialog.querySelector('.neos-two-factor__secret') + + // Init secret modal buttons + showSecretButton.onclick = function () { + secretDialog.showModal() + } + + secretDialogCloseButton.onclick = function () { + secretDialog.close() + } + + // Init overflow indicators + // Each character are wrapped in a span element (so we can have different styles for numbers and letters) + const allCharElements = Array.from(secretDisplay.querySelectorAll('span')) + const firstCharElement = allCharElements[0] + const lastCharElement = allCharElements[allCharElements.length - 1] + + const overflowIndicatorLeft = secretDialog.querySelector('.neos-two-factor__secret__overflow-indicator--left') + const overflowIndicatorRight = secretDialog.querySelector('.neos-two-factor__secret__overflow-indicator--right') + + const intersectionObserverOptions = { + threshold: 0.9 + } + + const firstCharIntersectionObserver = new IntersectionObserver(function (entries) { + // Hide or show indicator when first character is visible or not visible respectively + if (entries[0].isIntersecting) { + overflowIndicatorLeft.classList.add('neos-two-factor__hidden') + } else { + overflowIndicatorLeft.classList.remove('neos-two-factor__hidden') + } + }, intersectionObserverOptions) + + const lastCharIntersectionObserver = new IntersectionObserver(function (entries) { + // Hide or show indicator when last character is visible or not visible respectively + if (entries[0].isIntersecting) { + overflowIndicatorRight.classList.add('neos-two-factor__hidden') + } else { + overflowIndicatorRight.classList.remove('neos-two-factor__hidden') + } + }, intersectionObserverOptions) + + firstCharIntersectionObserver.observe(firstCharElement) + lastCharIntersectionObserver.observe(lastCharElement) + + // Init copy secret button + const copySecretButton = secretFormElement.querySelector('.neos-two-factor__secret__copy__button') + copySecretButton.onclick = async function () { + try { + // Copy secret to clipboard + await navigator.clipboard.writeText(secretInput.value) + // Disable button and show success indicator + copySecretButton.setAttribute('disabled', 'disabled') + copySecretButton.querySelectorAll('span').forEach(element => { + element.classList.toggle('neos-two-factor__hidden') }) - const intersectionObserverLastChar = new IntersectionObserver(function (entries) { - if (entries[0].isIntersecting) { - overflowIndicatorRight.classList.add('neos-two-factor__hidden') - } else { - overflowIndicatorRight.classList.remove('neos-two-factor__hidden') - } + // Wait for 1 second + await new Promise(function (resolve) { + setTimeout(resolve, 1000) }) - intersectionObserverFirstChar.observe(firstChar) - intersectionObserverLastChar.observe(lastChar) - - const copySecretButton = secretFormElement.querySelector('.neos-two-factor__secret__copy__button') - copySecretButton.onclick = function () { - - navigator.clipboard.writeText(secretInput.value) - .then(function () { - copySecretButton.querySelectorAll('span').forEach(element => { - element.classList.toggle('neos-two-factor__hidden') - }) - - return new Promise(function (resolve) { - setTimeout(resolve, 1000) - }) - }) - .then(function () { - copySecretButton.querySelectorAll('span').forEach(element => { - element.classList.toggle('neos-two-factor__hidden') - }) - }) - } - }) -}) + } finally { + // Re-enable button and hide success indicator + copySecretButton.removeAttribute('disabled') + copySecretButton.querySelectorAll('span').forEach(element => { + element.classList.toggle('neos-two-factor__hidden') + }) + } + } +}