enviroment-adviser
Version:
A permanent toast that notifies you that you are not in production
136 lines (116 loc) • 3.94 kB
text/typescript
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)
}