Calculater button on the corner of the screen, has dark/light theme switch and history.
目前為
// ==UserScript==
// @name Calculator
// @version 1.0
// @author Mane
// @license CC0-1.0
// @description Calculater button on the corner of the screen, has dark/light theme switch and history.
// @match *://*/*
// @run-at document-end
// @namespace https://greasyfork.org/users/1491313
// ==/UserScript==
;(function(){
'use strict';
// --- KEYS ---
const KEY_EXPR = 'cc_expr';
const KEY_HIST = 'cc_hist';
const KEY_THEME = 'cc_theme';
// --- STATE ---
let expr = localStorage.getItem(KEY_EXPR) || '';
let history = JSON.parse(localStorage.getItem(KEY_HIST) || '[]');
let theme = localStorage.getItem(KEY_THEME) || 'dark';
// --- STYLES ---
const css = `
:root {
--bg:#1e1e1e;--fg:#f1f1f1;--btn-bg:#333;--btn-fg:#f1f1f1;--accent:#007acc;
}
[data-theme="light"]{
--bg:#f1f1f1;--fg:#1e1e1e;--btn-bg:#ddd;--btn-fg:#1e1e1e;--accent:#005a9e;
}
#cc-toggle {
position:fixed;bottom:20px;right:20px;width:36px;height:36px;
background:var(--accent);color:#fff;border:none;border-radius:4px;
cursor:pointer;z-index:999999;font-size:18px;
}
#cc-panel {
position:fixed;bottom:60px;right:20px;width:280px;
background:var(--bg);color:var(--fg);padding:10px;
border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.3);
font-family:sans-serif;display:none;z-index:999999;
}
.small-btn {
position:absolute;width:24px;height:24px;
border:none;border-radius:4px;cursor:pointer;
background:var(--btn-bg);color:var(--btn-fg);
font-size:14px;line-height:1;
}
#cc-theme {top:8px;left:8px;}
#cc-history-toggle {top:8px;right:8px;}
#cc-display {
width:100%;height:36px;margin:32px 0 8px;
padding:0 8px;font-size:18px;text-align:right;
background:var(--btn-bg);color:var(--fg);border:none;
}
.cc-row{display:flex;margin:4px 0}
.cc-btn{
flex:1;margin:2px;height:32px;
background:var(--btn-bg);color:var(--btn-fg);
border:none;border-radius:4px;cursor:pointer;
font-size:16px;
}
.cc-op{background:var(--accent);color:#fff}
#cc-history {
display:none;margin-top:8px;
max-height:140px;overflow:auto;
background:var(--btn-bg);padding:6px;border-radius:4px;
}
#cc-history header{
display:flex;justify-content:space-between;align-items:center;
margin-bottom:4px;
}
#cc-history ul{
list-style:none;padding:0;margin:0;font-size:14px;
}
#cc-history li{
padding:2px 0;border-bottom:1px solid rgba(255,255,255,.1);
}
#cc-clear {
width:100%;margin-top:4px;padding:4px;
background:var(--btn-bg);color:var(--btn-fg);
border:none;border-radius:4px;cursor:pointer;
}
`;
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
// --- APPLY THEME ---
document.documentElement.setAttribute('data-theme', theme);
// --- BUILD UI ---
const toggle = document.createElement('button');
toggle.id = 'cc-toggle';
toggle.textContent = '🖩';
document.body.appendChild(toggle);
const panel = document.createElement('div');
panel.id = 'cc-panel';
panel.innerHTML = `
<button id="cc-theme" class="small-btn">${theme==='dark'?'☀️':'🌙'}</button>
<button id="cc-history-toggle" class="small-btn">📜</button>
<input id="cc-display" type="text" readonly />
<div class="cc-row">
<button class="cc-btn">7</button><button class="cc-btn">8</button>
<button class="cc-btn">9</button><button class="cc-btn cc-op">/</button>
</div>
<div class="cc-row">
<button class="cc-btn">4</button><button class="cc-btn">5</button>
<button class="cc-btn">6</button><button class="cc-btn cc-op">*</button>
</div>
<div class="cc-row">
<button class="cc-btn">1</button><button class="cc-btn">2</button>
<button class="cc-btn">3</button><button class="cc-btn cc-op">-</button>
</div>
<div class="cc-row">
<button class="cc-btn">0</button><button class="cc-btn">.</button>
<button class="cc-btn cc-op">=</button><button class="cc-btn cc-op">+</button>
</div>
<div class="cc-row">
<button class="cc-btn cc-op">(</button><button class="cc-btn cc-op">)</button>
<button class="cc-btn">C</button><button class="cc-btn">√</button>
</div>
<div id="cc-history">
<header>
<strong>History</strong>
<button id="cc-history-close" class="small-btn">✖️</button>
</header>
<ul></ul>
<button id="cc-clear">Clear</button>
</div>
`;
document.body.appendChild(panel);
// --- INITIALIZE ---
const disp = panel.querySelector('#cc-display');
disp.value = expr;
renderHistory();
// --- EVENTS ---
toggle.addEventListener('click', () => {
panel.style.display = panel.style.display==='block'?'none':'block';
});
panel.addEventListener('click', e => {
const b = e.target, v = b.textContent;
// theme toggle
if (b.id === 'cc-theme') {
theme = theme==='dark'?'light':'dark';
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem(KEY_THEME, theme);
b.textContent = theme==='dark'?'☀️':'🌙';
return;
}
// history open/close
if (b.id === 'cc-history-toggle') {
const h = panel.querySelector('#cc-history');
h.style.display = h.style.display==='block'?'none':'block';
renderHistory();
return;
}
if (b.id === 'cc-history-close') {
panel.querySelector('#cc-history').style.display = 'none';
return;
}
if (b.id === 'cc-clear') {
history = [];
saveHistory();
renderHistory();
return;
}
// calculator buttons
if (b.classList.contains('cc-btn')) {
if (v === 'C') {
expr = '';
} else if (v === '=') {
evaluate();
} else {
expr += v;
}
updateDisplay();
}
});
// --- CALC LOGIC ---
function evaluate(){
try {
const safe = expr
.replace(/√/g,'Math.sqrt')
.replace(/\b(sin|cos|tan|log)\b/g,'Math.$1');
const res = Function('return '+safe)();
history.unshift({input:expr,result:res});
history = history.slice(0,50);
saveHistory();
expr = String(res);
} catch {
expr = 'Error';
}
}
function updateDisplay(){
disp.value = expr;
localStorage.setItem(KEY_EXPR, expr);
}
// --- HISTORY & STORAGE ---
function saveHistory(){
localStorage.setItem(KEY_HIST, JSON.stringify(history));
}
function renderHistory(){
const ul = panel.querySelector('#cc-history ul');
ul.innerHTML = history.map(it=>
`<li>${it.input} = ${it.result}</li>`
).join('');
}
})();