UNPKG

enviroment-adviser

Version:

A permanent toast that notifies you that you are not in production

136 lines (116 loc) 3.94 kB
const css = ` #environment-adviser { background-color: #ff0000; color: white; padding: 10px 20px; border-radius: 5px; font-family: sans-serif; font-weight: bold; cursor: pointer; z-index: 9999; } ` function addStyles() { const styleSheet = document.createElement('style') styleSheet.type = 'text/css' styleSheet.innerText = css document.head.appendChild(styleSheet) } export function showEnvironmentAdviser(options?: { scale?: number opacity?: number animation?: 'none' | 'slide' | 'spin' | 'pulse' transitionSpeed?: number }) { if (process.env.NODE_ENV === 'production') { return } const scale = options?.scale ?? 1 const opacity = options?.opacity ?? 1 const animation = options?.animation ?? 'none' const speedMultiplier = options?.transitionSpeed ?? 1 const duration = 1 / speedMultiplier const adviser = document.createElement('div') adviser.id = 'environment-adviser' adviser.textContent = `ENVIRONMENT: ${process.env.NODE_ENV}` adviser.style.position = 'fixed' adviser.style.backgroundColor = '#ff0000' adviser.style.color = 'white' adviser.style.padding = `${0.625 * scale}rem ${1.25 * scale}rem` adviser.style.borderRadius = `${0.3125 * scale}rem` adviser.style.fontFamily = 'sans-serif' adviser.style.fontWeight = 'bold' adviser.style.fontSize = `${1 * scale}rem` adviser.style.cursor = 'pointer' adviser.style.zIndex = '9999' adviser.style.opacity = opacity.toString() const styleSheet = document.createElement('style') styleSheet.innerHTML = ` @keyframes adviser-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .adviser-spin { animation: adviser-spin ${duration}s linear; } @keyframes adviser-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } } .adviser-pulse { animation: adviser-pulse ${duration}s ease-in-out; } ` document.head.appendChild(styleSheet) document.body.appendChild(adviser) const corners = ['top-right', 'bottom-right', 'bottom-left', 'top-left'] let currentCornerIndex = 0 let isMoving = false const setPosition = (cornerName: string) => { const offsetRem = 1.25 * scale const { offsetHeight: elHeight, offsetWidth: elWidth } = adviser adviser.style.right = '' adviser.style.bottom = '' adviser.style.top = '' adviser.style.left = '' switch (cornerName) { case 'top-right': adviser.style.top = `${offsetRem}rem` adviser.style.left = `calc(100vw - ${elWidth}px - ${offsetRem}rem)` break case 'bottom-right': adviser.style.top = `calc(100vh - ${elHeight}px - ${offsetRem}rem)` adviser.style.left = `calc(100vw - ${elWidth}px - ${offsetRem}rem)` break case 'bottom-left': adviser.style.top = `calc(100vh - ${elHeight}px - ${offsetRem}rem)` adviser.style.left = `${offsetRem}rem` break case 'top-left': adviser.style.top = `${offsetRem}rem` adviser.style.left = `${offsetRem}rem` break } } const moveAdviser = () => { if (isMoving) return isMoving = true currentCornerIndex = (currentCornerIndex + 1) % corners.length const nextCorner = corners[currentCornerIndex] if (animation === 'slide') { adviser.style.transition = `top ${duration}s linear, left ${duration}s linear` } else { adviser.style.transition = `all ${duration}s ease-in-out` } if (animation === 'spin' || animation === 'pulse') { adviser.classList.add(`adviser-${animation}`) } setPosition(nextCorner) setTimeout(() => { isMoving = false if (animation === 'spin' || animation === 'pulse') { adviser.classList.remove(`adviser-${animation}`) } }, duration * 1000) } setTimeout(() => { adviser.style.transition = 'none' setPosition(corners[currentCornerIndex]) }, 50) window.addEventListener('resize', () => { adviser.style.transition = 'none' setPosition(corners[currentCornerIndex]) }) adviser.addEventListener('mouseenter', moveAdviser) adviser.addEventListener('click', moveAdviser) }