Skip to content

Commit

Permalink
refactor: expand code button
Browse files Browse the repository at this point in the history
  • Loading branch information
yilanboy committed Nov 8, 2024
1 parent 76b90a0 commit a77bacc
Showing 1 changed file with 119 additions and 42 deletions.
161 changes: 119 additions & 42 deletions resources/ts/code-block-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ declare global {
}

// use Tailwind CSS class names
const baseButtonClassName: string[] = [
const BASE_BUTTON_CLASS_NAME: string[] = [
'fixed',
'size-8',
'flex',
Expand All @@ -26,31 +26,41 @@ const baseButtonClassName: string[] = [
'duration-200',
];

const checkIcon: string = `
const CHECK_ICON_SVG: string = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425z"/>
</svg>
`;

const clipboardIcon: string = `
const CLIPBOARD_ICON_SVG: string = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M10 1.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5zm-5 0A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5v1A1.5 1.5 0 0 1 9.5 4h-3A1.5 1.5 0 0 1 5 2.5zm-2 0h1v1A2.5 2.5 0 0 0 6.5 5h3A2.5 2.5 0 0 0 12 2.5v-1h1a2 2 0 0 1 2 2V14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3.5a2 2 0 0 1 2-2"/>
</svg>
`;

const arrowsAngleExpandIcon: string = `
const ARROWS_ANGLE_EXPAND_ICON_SVG: string = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrows-angle-expand" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707m4.344-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707"/>
</svg>
`;

const X_CIRCLE_FILL_ICON_SVG: string = `
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="size-10" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293z"/>
</svg>
`;

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) {
Expand All @@ -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,
);
Expand All @@ -73,62 +83,139 @@ function createCopyCodeButton(code: string): HTMLButtonElement {
return copyButton;
}

function modalTemplate(html: string, closeModalButtonId: string): string {
function modalTemplate(html: string): string {
return `
<div class="relative z-30">
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity backdrop-blur-md"></div>
<!-- Background backdrop, show/hide based on modal state -->
<div
id="${BACKGROUND_BACKDROP_ID}"
class="fixed inset-0 bg-gray-500/75 transition-opacity backdrop-blur-md ease-in duration-200 opacity-0"
></div>
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
<div class="flex min-h-full justify-center p-4 text-center items-center">
<div class="relative transform overflow-hidden rounded-lg text-left transition-all sm:w-full sm:max-w-6xl">
<!-- Modal panel, show/hide based on modal state. -->
<div
id="${MODAL_PANEL_ID}"
class="relative transform overflow-hidden rounded-lg text-left transition-all sm:w-full sm:max-w-6xl ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
${html}
</div>
</div>
</div>
<div class="fixed z-10 right-10 top-10">
<button
id="${closeModalButtonId}"
id="${CLOSE_MODAL_BUTTON_ID}"
type="button"
class="text-gray-200 hover:text-gray-50"
>
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="size-10" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293z"/>
</svg>
${X_CIRCLE_FILL_ICON_SVG}
</button>
</div>
</div>
`;
}

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 };
Expand All @@ -138,8 +225,6 @@ window.codeBlockHelper = function (element: HTMLElement): void {
const preTags: HTMLCollectionOf<HTMLPreElement> =
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')) {
Expand All @@ -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
Expand All @@ -191,7 +270,5 @@ window.codeBlockHelper = function (element: HTMLElement): void {
},
{ once: true },
);

index += 1;
}
};

0 comments on commit a77bacc

Please sign in to comment.