diff --git a/resources/ts/code-block-helper.ts b/resources/ts/code-block-helper.ts index 34f7e79c..993041d0 100644 --- a/resources/ts/code-block-helper.ts +++ b/resources/ts/code-block-helper.ts @@ -5,7 +5,7 @@ declare global { } // use Tailwind CSS class names -const baseButtonClassName: string[] = [ +const BASE_BUTTON_CLASS_NAME: string[] = [ 'fixed', 'size-8', 'flex', @@ -26,31 +26,41 @@ const baseButtonClassName: string[] = [ 'duration-200', ]; -const checkIcon: string = ` +const CHECK_ICON_SVG: string = ` `; -const clipboardIcon: string = ` +const CLIPBOARD_ICON_SVG: string = ` `; -const arrowsAngleExpandIcon: string = ` +const ARROWS_ANGLE_EXPAND_ICON_SVG: string = ` `; +const X_CIRCLE_FILL_ICON_SVG: string = ` + + + +`; + +const BACKGROUND_BACKDROP_ID: string = 'expand-code-block-background-backdrop'; +const MODAL_PANEL_ID: string = 'expand-code-block-modal-panel'; +const CLOSE_MODAL_BUTTON_ID: string = 'expand-code-block-close-modal-button'; + function createCopyCodeButton(code: string): HTMLButtonElement { // create copy button const copyButton: HTMLButtonElement = document.createElement('button'); - copyButton.classList.add(...baseButtonClassName); + copyButton.classList.add(...BASE_BUTTON_CLASS_NAME); // set button position copyButton.classList.add('top-2', 'right-2'); - copyButton.innerHTML = clipboardIcon; + copyButton.innerHTML = CLIPBOARD_ICON_SVG; // when copy button is clicked, copy code to clipboard copyButton.addEventListener('click', function (this: HTMLButtonElement) { @@ -61,10 +71,10 @@ function createCopyCodeButton(code: string): HTMLButtonElement { ); // change button icon to "Copied!" for 2 seconds - this.innerHTML = checkIcon; + this.innerHTML = CHECK_ICON_SVG; setTimeout( function (this: HTMLButtonElement) { - this.innerHTML = clipboardIcon; + this.innerHTML = CLIPBOARD_ICON_SVG; }.bind(this), 2000, ); @@ -73,14 +83,22 @@ function createCopyCodeButton(code: string): HTMLButtonElement { return copyButton; } -function modalTemplate(html: string, closeModalButtonId: string): string { +function modalTemplate(html: string): string { return `
-
+ +
-
+ +
${html}
@@ -88,47 +106,116 @@ function modalTemplate(html: string, closeModalButtonId: string): string {
`; } -function createExpandCodeButton( - preOuterHtml: string, - closeExpandButtonId: string, - modalSiblingNode: HTMLElement, -): { expandButton: HTMLButtonElement; modal: HTMLDivElement } { +function createExpandCodeButton(preOuterHtml: string): { + expandButton: HTMLButtonElement; + modal: HTMLDivElement; +} { const expandButton: HTMLButtonElement = document.createElement('button'); - expandButton.classList.add(...baseButtonClassName); + expandButton.classList.add(...BASE_BUTTON_CLASS_NAME); expandButton.classList.add('top-2', 'right-12'); - expandButton.innerHTML = arrowsAngleExpandIcon; + expandButton.innerHTML = ARROWS_ANGLE_EXPAND_ICON_SVG; - const modalInnerHtml = modalTemplate(preOuterHtml, closeExpandButtonId); + const modalInnerHtml = modalTemplate(preOuterHtml); const modal: HTMLDivElement = document.createElement('div'); - modal.classList.add('hidden'); modal.innerHTML = modalInnerHtml; - modalSiblingNode.parentNode?.insertBefore(modal, modalSiblingNode); - + // transport modal to another part of the DOM on the page entirely expandButton.addEventListener('click', function (this: HTMLButtonElement) { - modal.classList.remove('hidden'); + document.body.appendChild(modal); document.body.style.overflow = 'hidden'; - }); - const closeExpandButton = document.getElementById(closeExpandButtonId); + const backgroundBackdrop = document.getElementById( + BACKGROUND_BACKDROP_ID, + ); + + const modalPanel = document.getElementById(MODAL_PANEL_ID); - closeExpandButton?.addEventListener('click', function () { - modal.classList.add('hidden'); - document.body.style.overflow = ''; + setTimeout(() => { + backgroundBackdrop?.classList.remove( + 'ease-in', + 'duration-200', + 'opacity-0', + ); + + backgroundBackdrop?.classList.add( + 'ease-out', + 'duration-300', + 'opacity-100', + ); + + modalPanel?.classList.remove( + 'ease-in', + 'duration-200', + 'opacity-0', + 'translate-y-4', + 'sm:translate-y-0', + 'sm:scale-95', + ); + + modalPanel?.classList.add( + 'ease-out', + 'duration-300', + 'opacity-100', + 'translate-y-0', + 'sm:scale-100', + ); + }, 100); + + const closeExpandButton = document.getElementById( + CLOSE_MODAL_BUTTON_ID, + ); + + closeExpandButton?.addEventListener( + 'click', + () => { + backgroundBackdrop?.classList.remove( + 'ease-out', + 'duration-300', + 'opacity-100', + ); + + backgroundBackdrop?.classList.add( + 'ease-in', + 'duration-200', + 'opacity-0', + ); + + modalPanel?.classList.remove( + 'ease-out', + 'duration-300', + 'opacity-100', + 'translate-y-0', + 'sm:scale-100', + ); + + modalPanel?.classList.add( + 'ease-in', + 'duration-20', + 'opacity-0', + 'translate-y-4', + 'sm:translate-y-0', + 'sm:scale-95', + ); + + setTimeout(() => { + document.body.removeChild(modal); + document.body.style.overflow = ''; + }, 300); + }, + { once: true }, + ); }); return { expandButton: expandButton, modal: modal }; @@ -138,8 +225,6 @@ window.codeBlockHelper = function (element: HTMLElement): void { const preTags: HTMLCollectionOf = element.getElementsByTagName('pre'); - let index = 0; - // add copy button to all pre tags for (const preTag of preTags) { if (preTag.classList.contains('code-block-helper-added')) { @@ -161,14 +246,8 @@ window.codeBlockHelper = function (element: HTMLElement): void { code.innerText, ); - // start to create expand code button and modal... - const closeExpandButtonId = - 'expand-code-block-close-button-' + index.toString(); - const { expandButton, modal } = createExpandCodeButton( preTag.outerHTML, - closeExpandButtonId, - element, ); // append these button in pre tag @@ -191,7 +270,5 @@ window.codeBlockHelper = function (element: HTMLElement): void { }, { once: true }, ); - - index += 1; } };