Simple Modal Popup

Upload a file in the Ghost editor and display the file contents in a popup modal window...

... to upload the file I used the File Upload Card in the post editor ...

Now I want to display the contents of that file in a Modal Window when a link in my post is clicked...

PDF in a Modal...

Uploading a file into your Ghost post displays the file in the post like so...

HOW-TO

  1. This goes in the Header Code Injection...
<style>
.sp-wrapper {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgb(0, 0, 0, 0.5);
    height: 100%;
    width: 100%;
    overflow-y: auto;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    z-index: 1000;
}

.sp-wrapper .content {
    border-radius: 4px;
    min-height: 100px;
    max-width: 800px;
    width: 90%;
    background-color: #fff;
    position: absolute;
    margin: 1em 0;
    overflow: hidden;
}

.sp-wrapper .content.into-view {
    top: 0;
}

.center-all {
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
}

.sp-source {
    display: none;
}

.sp-wrapper .sp-close-button {
    height: 30px;
    width: 30px;
    position: absolute;
    top: 0;
    right: 0;
    background-color: #eee;
    cursor: pointer;
}

.sp-wrapper .sp-close-button::before {
    content: 'x';
    height: auto;
    width: auto;
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}

.sp-wrapper.fadeIn {
    -webkit-animation: fadeIn .25s both;
    animation: fadeIn .25s both
}

@-webkit-keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

@keyframes fadeIn {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

.sp-wrapper.fadeOut {
    -webkit-animation: fadeOut .25s both;
    animation: fadeOut .25s both
}

@-webkit-keyframes fadeOut {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0;
    }
}

@keyframes fadeOut {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0;
    }
}

.sp-wrapper .fadeInDown {
    -webkit-animation: fadeInDown .35s both;
    animation: fadeInDown .35s both
}

@-webkit-keyframes fadeInDown {
    0% {
        opacity: 0;
        margin-top: -20px
    }
    100% {
        opacity: 1;
    }
}

@keyframes fadeInDown {
    0% {
        opacity: 0;
        margin-top: -20px
    }
    100% {
        opacity: 1;
    }
}

.sp-wrapper .fadeOutUp {
    -webkit-animation: fadeOutUp .35s both;
    animation: fadeOutUp .35s both
}

@-webkit-keyframes fadeOutUp {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        margin-top: -20px
    }
}

@keyframes fadeOutUp {
    0% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        margin-top: -20px
    }
}

.sp-wrapper .zoomIn {
    -webkit-animation: zoomIn .15s both;
    animation: zoomIn .15s both;
}

@-webkit-keyframes zoomIn {
    0% {
        opacity: 0;
        -webkit-transform: scale(.95);
        transform: scale(.95);
    }
    100% {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
}

@keyframes zoomIn {
    0% {
        opacity: 0;
        -webkit-transform: scale(.95);
        transform: scale(.95);
    }
    100% {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
}

.sp-wrapper .zoomOut {
    -webkit-animation: zoomOut .15s both;
    animation: zoomOut .15s both;
}

@-webkit-keyframes zoomOut {
    0% {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
    100% {
        opacity: 0;
        -webkit-transform: scale(.85);
        transform: scale(.85);
    }
}

@keyframes zoomOut {
    0% {
        opacity: 1;
        -webkit-transform: scale(1);
        transform: scale(1);
    }
    100% {
        opacity: 0;
        -webkit-transform: scale(.85);
        transform: scale(.85);
    }
}
</style>

2.  This goes in an HTML Card in the post editor...

<a href="#" class="sp-trigger" data-target="source1">PDF in a Modal...</a>
<div class="sp-source" id="source1">
<iframe src="https://ghost-o-matic.com/content/files/2022/06/JENS-DAD-HAROLD-WALLACE.pdf" frameborder="0" style="width:100%; height:90vh; margin:0"></iframe>
</div>

3.  This goes in the Footer Code Injection...

<script>
const SimplePopup = (function() {
    let wrapper, instance, closeButton, content, _params, t, isAnimating = false,
        animationType;
    const defineProperty = (obj, prop) => {
        obj = obj || {}
        obj[prop] = obj[prop] || '';
        return obj;
    };
    const centerize = () => {
        // center the content's height is greater window's height
        if (content.scrollHeight >= window.innerHeight) {
            content.classList.add('into-view');
        } else {
            content.classList.remove('into-view');
        }
    };

    function SimplePopup() {}
    SimplePopup.prototype.openModal = (params, cb) => {

        // set params
        _params = params;

        // set flag when animation in progress
        isAnimating = true;

        // set animation type
        _params.styles = defineProperty(_params.styles, 'position');

        if (_params.styles.animation) {
            animationType = _params.styles.position === 'center' ? 'zoomIn' : 'fadeInDown';
        }

        wrapper = document.createElement('div');
        wrapper.setAttribute('class', `sp-wrapper ${_params.styles.animation && 'fadeIn'}  ${_params.styles.position === 'center' ? 'center-all' : ''}`);

        // populate the content
        content = document.createElement('div');
        content.setAttribute('class', `content ${animationType}`);
        const tempDiv = document.createElement('div');
        tempDiv.innerHTML = params.content;
        content.appendChild(tempDiv);

        //apply inline style
        const maxWidth = params.styles.maxWidth ? `max-width: ${params.styles.maxWidth}` : '';
        const duration = params.styles.duration ? `; animation-duration:${params.styles.duration/1000}s` : '';
        content.setAttribute('style', `${maxWidth}${_params.styles.animation && duration}`);


        // add close button
        if (_params.styles.closeButton) {
            const closeButton = document.createElement('div');
            closeButton.setAttribute('class', 'sp-close-button');
            content.prepend(closeButton);
        }

        // add content to wrapper
        wrapper.appendChild(content);

        // add to body
        document.body.prepend(wrapper);

        t && clearTimeout(t);

        t = setTimeout(() => {
            isAnimating = false;
        }, params.styles.duration);

        cb && cb();
    };
    SimplePopup.prototype.closeModal = (e) => {
        if (isAnimating) return;
        const classes = e.srcElement.getAttribute('class');
        if (classes && (classes.indexOf('sp-wrapper') > -1 || classes.indexOf('sp-close-button') > -1)) {
            if (_params.styles.animation) {
                wrapper.classList.remove('fadeIn');
                wrapper.classList.add('fadeOut');

                if (_params.styles.position !== 'center') {
                    content.classList.remove('fadeInDown');
                    content.classList.add('fadeOutUp');
                } else {
                    content.classList.remove('zoomIn');
                    content.classList.add('zoomOut');
                }

                setTimeout(() => {
                    wrapper && wrapper.parentNode.removeChild(wrapper);
                }, _params.styles.duration || 350)
            } else {
                wrapper.parentNode.removeChild(wrapper);
            }

        }
    };
    SimplePopup.prototype.init = (params) => {
        let triggers = document.querySelectorAll('.sp-trigger');
        triggers.forEach((item) => {
            item.addEventListener('click', (e) => {
                const target = e.target;
                const id = target.getAttribute('data-target');
                const source = document.querySelector(`#${id}`);
                if (!source) {
                    alert('Error: Source unknown.')
                    return;
                }
                instance.openModal({ content: source.innerHTML, styles: params }, function() {
                    //load close wrapper
                    wrapper && wrapper.removeEventListener('click', instance.closeModal);
                    wrapper && wrapper.addEventListener('click', instance.closeModal);
                    //load close button
                    closeButton && closeButton.removeEventListener('click', instance.closeModal);
                    closeButton && closeButton.addEventListener('add', instance.closeModal);

                    centerize();

                });
            });
        });
        window.addEventListener('resize', () => centerize);
    };
    if (!instance) {
        instance = new SimplePopup();
    }
    return instance;
})();
</script>

<script>
        SimplePopup.init({
            maxWidth: '500px',
            duration: '200',
            closeButton: true,
            animation: true
        });
</script>