modals - 02

revision:


stacked-up modals.

Click this trigger..to open a modal.

Close a modal by: 1/ clicking off to the side, 2/ clicking the X, or 3/ pressing Escape.

code:
                <div class="spec">
                    <p><a href="#" class="modal-trigger" data-modal-id="modal1">
                    Click this trigger</a>..to open a modal.</p>
                    <p>Close a modal by: 1/ clicking off to the side, 2/ clicking the 
                    X, or 3/ pressing Escape.</p>
        
                    <div class="modal-wrapper" id="modal1">
                        <section class="modal-window">
                            <header class="modal-header">
                                <h3>The first modal</h3>
                                <button type="button" class="close-modal-button" 
                                aria-label="Close modal window">X</button>
                            </header>
                            <p>You have opened the first modal!</p>
                            <p>Now, open the second modal by clicking the link.</p> 
                            <a href="#" class="modal-trigger" data-modal-id="modal2">
                            Second modal</a> !</p>
                        </section>
                    </div>
        
                    <div class="modal-wrapper" id="modal2">
                        <section class="modal-window">
                            <header class="modal-header">
                                <h3>The second modal. 🤯</h3>
                                <button type="button" class="close-modal-button" 
                                aria-label="Close modal window">X</button>
                            </header>
                            <p>Nice, the second modal.</p>
                        </section>
                    </div>
                </div>
                <style>
                    .modal-wrapper {align-items: center; bottom: 0; display: flex; flex-wrap: wrap;
                        height: 100vh;justify-content: center;left: 0; opacity: 0;position: fixed; 
                        right: 0; transition: all 0.2s ease-in-out; visibility: hidden; width: 40%;
                        z-index: 1000;}
                    .modal-wrapper.visible {opacity: 1;visibility: visible;}
                    .modal-window {background-image: linear-gradient(red, yellow, black);border-radius:
                        1vw; box-shadow: 0 .3vw .7vw rgba(0, 0, 0, 0.3); padding: 2vw; transform: scale(0); 
                        transition: 0.2s ease-in-out all;}
                    .modal-wrapper.visible .modal-window {transform: scale(1);}
                    .modal-header {align-items: center;border-bottom: 0.2vw solid blue; display: flex; 
                        justify-content: space-between; margin-bottom: 2vw; padding-bottom: 2vw;}
                    .close-modal-button {border: none; background-color: transparent; color: darkgreen; 
                        cursor: pointer; font-size: 2vw; padding: 0.2vw; }
                    .close-modal-button:hover {color: black;}
                    .modal-trigger {color: blue; cursor: pointer; text-decoration: underline;}
                </style>
                <script>
                    // Stack of modals
                    let currentlyOpenModals = [];
        
                    const noModalsOpen = () => !currentlyOpenModals.length;
        
                    const openModal = modalId => {
                        const modalWrapper = document.getElementById(modalId);
                        modalWrapper.classList.add("visible");
                        currentlyOpenModals.push(modalWrapper);
                    };
        
                    // By definition, it's always the topmost modal that will be closed first
                    const closeTopmostModal = () => {
                        if (noModalsOpen()) {
                            return;
                        }
        
                        const modalWrapper = currentlyOpenModals[currentlyOpenModals.length - 1];
                        modalWrapper.classList.remove("visible");
                        currentlyOpenModals.pop();
                    };
        
                    const modalTriggers = document.querySelectorAll(".modal-trigger");
                    modalTriggers.forEach(modalTrigger => {
                        modalTrigger.addEventListener("click", clickEvent => {
                            const trigger = clickEvent.target;
                            const modalId = trigger.getAttribute("data-modal-id");
                            openModal(modalId);
                        });
                    });
        
                    // Otherwise, clicking the content of a modal will propagate the click to the 
                    modal wrapper,
                    // and that will close the entire thing. That's not what we want!
                    document.querySelectorAll(".modal-window").forEach(modal => {
                        modal.addEventListener("click", clickEvent => {
                            clickEvent.stopPropagation();
                        });
                    });
        
                    const modalWrappers = document.querySelectorAll(".modal-wrapper");
                    modalWrappers.forEach(modalWrapper => {
                        modalWrapper.addEventListener("click", () => {
                            closeTopmostModal();
                        });
                    });
        
                    document.querySelectorAll(".close-modal-button").forEach(closeModalButton => {
                        closeModalButton.addEventListener("click", () => {
                            closeTopmostModal();
                        });
                    });
        
                    document.body.addEventListener("keyup", keyEvent => {
                        if (keyEvent.key === "Escape") {
                            closeTopmostModal();
                        }
                    });
                </script>