// ==UserScript==
// @name cool calculator
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Draggable, resizable, fullscreen, pink-purple gradient calculator with exponentiation, sqrt, parentheses, and persistent state by Leon Luk.
// @author Leon Luk
// @match *://*/*
// @grant none
// @license Proprietary
// ==/UserScript==
(function() {
'use strict';
const STORAGE_POS = 'leonluk_calc_pos';
const STORAGE_OPEN = 'leonluk_calc_open';
const STORAGE_FULLSCREEN = 'leonluk_calc_fullscreen';
const button = document.createElement('button');
button.innerText = '🧮 Calculator';
Object.assign(button.style, {
position: 'fixed',
top: '50%',
left: '10px',
transform: 'translateY(-50%)',
zIndex: '999999',
padding: '10px 15px',
fontSize: '14px',
background: 'linear-gradient(135deg,#d946ef,#7c3aed)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
transition: 'opacity 0.3s ease'
});
button.onmouseenter = () => button.style.opacity = '0.8';
button.onmouseleave = () => button.style.opacity = '1';
document.body.appendChild(button);
const calc = document.createElement('div');
Object.assign(calc.style, {
position: 'fixed',
top: '50%',
left: '-300px',
width: '300px',
height: 'auto',
padding: '15px',
background: 'linear-gradient(135deg,#ec4899,#8b5cf6)',
color: 'white',
borderRadius: '10px',
boxShadow: '4px 0 15px rgba(0,0,0,0.6)',
zIndex: '1000000',
transition: 'left 0.5s cubic-bezier(0.25,1,0.3,1), width 0.3s, height 0.3s',
fontFamily: 'monospace',
opacity: '0.97',
cursor: 'grab',
overflow: 'hidden'
});
document.body.appendChild(calc);
const savedPos = JSON.parse(localStorage.getItem(STORAGE_POS));
const savedOpen = localStorage.getItem(STORAGE_OPEN);
const savedFullscreen = localStorage.getItem(STORAGE_FULLSCREEN);
if (savedPos) {
calc.style.left = savedPos.left + 'px';
calc.style.top = savedPos.top + 'px';
calc.style.width = (savedPos.width || 300) + 'px';
calc.style.height = (savedPos.height || 'auto') + 'px';
calc.style.transform = 'none';
}
calc.innerHTML = `
<div id="calc-header" style="display:flex;justify-content:space-between;align-items:center;font-weight:bold;margin-bottom:5px;cursor:move;font-size:16px;">
<span>Calculator</span>
<div>
<button id="fullscreen-btn" style="background:none;border:none;color:white;font-size:18px;cursor:pointer;line-height:1;padding:0;margin-right:5px;">🗖</button>
<button id="minimize-btn" style="background:none;border:none;color:white;font-size:20px;cursor:pointer;line-height:1;padding:0;">—</button>
</div>
</div>
<input type="text" id="calc-display" readonly style="width:100%;padding:10px;font-size:18px;border:none;border-radius:5px;text-align:right;background:rgba(0,0,0,0.3);color:white;margin-bottom:5px;">
<div id="calc-buttons" style="display:grid;grid-template-columns:repeat(5,1fr);gap:5px;margin-bottom:5px;"></div>
<div style="text-align:right;font-size:10px;opacity:0.8;">by Leon Luk</div>
`;
const display = calc.querySelector('#calc-display');
const buttonsContainer = calc.querySelector('#calc-buttons');
const minimizeBtn = calc.querySelector('#minimize-btn');
const fullscreenBtn = calc.querySelector('#fullscreen-btn');
const buttons = [
'7','8','9','/','C',
'4','5','6','*','(',
'1','2','3','-',')',
'0','.','=','+','^',
'√'
];
buttons.forEach(key => {
const btn = document.createElement('button');
btn.innerText = key;
Object.assign(btn.style, {
padding: '10px',
fontSize: '16px',
border: 'none',
borderRadius: '5px',
background: 'rgba(255,255,255,0.15)',
color: 'white',
cursor: 'pointer',
transition: 'background 0.2s ease, transform 0.1s ease'
});
btn.onmouseenter = () => btn.style.background = 'rgba(255,255,255,0.25)';
btn.onmouseleave = () => btn.style.background = 'rgba(255,255,255,0.15)';
btn.onmousedown = () => btn.style.transform = 'scale(0.95)';
btn.onmouseup = () => btn.style.transform = 'scale(1)';
btn.addEventListener('click', () => {
if(key === 'C') { display.value = ''; }
else if(key === '=') {
try {
// Replace ^ with ** for exponentiation
const expValue = display.value.replace(/\^/g,'**').replace(/√/g,'Math.sqrt');
display.value = eval(expValue);
} catch {
display.value = 'Error';
}
} else {
display.value += key;
}
});
buttonsContainer.appendChild(btn);
});
let isOpen = false;
if(savedOpen === 'true'){ isOpen = true; calc.style.left = '70px'; }
let isFullscreen = false;
if(savedFullscreen === 'true'){
isFullscreen = true;
calc.style.left = '0';
calc.style.top = '0';
calc.style.width = '100%';
calc.style.height = '100%';
}
button.addEventListener('click', () => {
isOpen = !isOpen;
calc.style.left = isOpen ? '70px' : '-300px';
localStorage.setItem(STORAGE_OPEN, isOpen);
});
minimizeBtn.addEventListener('click', () => {
calc.style.left = '-300px';
isOpen = false;
localStorage.setItem(STORAGE_OPEN, isOpen);
});
fullscreenBtn.addEventListener('click', () => {
isFullscreen = !isFullscreen;
if(isFullscreen){
calc.style.left = '0';
calc.style.top = '0';
calc.style.width = '100%';
calc.style.height = '100%';
} else {
const pos = JSON.parse(localStorage.getItem(STORAGE_POS)) || {left:70,top:50,width:300,height:'auto'};
calc.style.left = pos.left + 'px';
calc.style.top = pos.top + 'px';
calc.style.width = (pos.width || 300) + 'px';
calc.style.height = (pos.height || 'auto') + 'px';
}
localStorage.setItem(STORAGE_FULLSCREEN, isFullscreen);
});
const header = calc.querySelector('#calc-header');
let dragging = false, offsetX=0, offsetY=0;
header.addEventListener('mousedown', e => {
dragging = true;
offsetX = e.clientX - calc.getBoundingClientRect().left;
offsetY = e.clientY - calc.getBoundingClientRect().top;
calc.style.transition = 'none';
calc.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', e => {
if(!dragging) return;
e.preventDefault();
if(!isFullscreen){
const left = e.clientX - offsetX;
const top = e.clientY - offsetY;
calc.style.left = left + 'px';
calc.style.top = top + 'px';
calc.style.transform = 'none';
}
});
document.addEventListener('mouseup', () => {
if(dragging){
dragging = false;
calc.style.cursor = 'grab';
calc.style.transition = 'left 0.5s cubic-bezier(0.25,1,0.3,1)';
localStorage.setItem(STORAGE_POS, JSON.stringify({
left: parseInt(calc.style.left),
top: parseInt(calc.style.top),
width: parseInt(calc.style.width),
height: calc.style.height
}));
}
});
// Resizer
const resizer = document.createElement('div');
Object.assign(resizer.style,{
width:'10px', height:'10px', position:'absolute',
right:0, bottom:0, cursor:'se-resize', background:'rgba(255,255,255,0.2)'
});
calc.appendChild(resizer);
let resizing = false;
resizer.addEventListener('mousedown', e => { resizing = true; e.preventDefault(); });
document.addEventListener('mousemove', e => {
if(!resizing) return;
e.preventDefault();
const w = e.clientX - calc.getBoundingClientRect().left;
const h = e.clientY - calc.getBoundingClientRect().top;
calc.style.width = w + 'px';
calc.style.height = h + 'px';
});
document.addEventListener('mouseup', () => {
if(resizing){
resizing = false;
localStorage.setItem(STORAGE_POS, JSON.stringify({
left: parseInt(calc.style.left),
top: parseInt(calc.style.top),
width: parseInt(calc.style.width),
height: calc.style.height
}));
}
});
})();