Spaces:
Sleeping
Sleeping
| import { useState, useCallback } from 'react'; | |
| export default function Calculator() { | |
| const [display, setDisplay] = useState('0'); | |
| const [previousValue, setPreviousValue] = useState(null); | |
| const [operation, setOperation] = useState(null); | |
| const [waitingForOperand, setWaitingForOperand] = useState(false); | |
| const [history, setHistory] = useState([]); | |
| const inputDigit = useCallback((digit) => { | |
| if (waitingForOperand) { | |
| setDisplay(digit); | |
| setWaitingForOperand(false); | |
| } else { | |
| setDisplay(display === '0' ? digit : display + digit); | |
| } | |
| }, [display, waitingForOperand]); | |
| const inputDecimal = useCallback(() => { | |
| if (waitingForOperand) { | |
| setDisplay('0.'); | |
| setWaitingForOperand(false); | |
| } else if (!display.includes('.')) { | |
| setDisplay(display + '.'); | |
| } | |
| }, [display, waitingForOperand]); | |
| const clear = useCallback(() => { | |
| setDisplay('0'); | |
| setPreviousValue(null); | |
| setOperation(null); | |
| setWaitingForOperand(false); | |
| }, []); | |
| const toggleSign = useCallback(() => { | |
| setDisplay(String(-parseFloat(display))); | |
| }, [display]); | |
| const percentage = useCallback(() => { | |
| setDisplay(String(parseFloat(display) / 100)); | |
| }, [display]); | |
| const performOperation = useCallback((nextOperation) => { | |
| const inputValue = parseFloat(display); | |
| if (previousValue === null) { | |
| setPreviousValue(inputValue); | |
| } else if (operation) { | |
| const currentValue = previousValue || 0; | |
| let result; | |
| switch (operation) { | |
| case '+': | |
| result = currentValue + inputValue; | |
| break; | |
| case '-': | |
| result = currentValue - inputValue; | |
| break; | |
| case '×': | |
| result = currentValue * inputValue; | |
| break; | |
| case '÷': | |
| result = currentValue / inputValue; | |
| break; | |
| default: | |
| result = inputValue; | |
| } | |
| setDisplay(String(result)); | |
| setPreviousValue(result); | |
| // Add to history | |
| setHistory(prev => [...prev, `${currentValue} ${operation} ${inputValue} = ${result}`].slice(-5)); | |
| } | |
| setWaitingForOperand(true); | |
| setOperation(nextOperation); | |
| }, [display, operation, previousValue]); | |
| const calculate = useCallback(() => { | |
| if (!operation || previousValue === null) return; | |
| const inputValue = parseFloat(display); | |
| let result; | |
| switch (operation) { | |
| case '+': | |
| result = previousValue + inputValue; | |
| break; | |
| case '-': | |
| result = previousValue - inputValue; | |
| break; | |
| case '×': | |
| result = previousValue * inputValue; | |
| break; | |
| case '÷': | |
| result = previousValue / inputValue; | |
| break; | |
| default: | |
| result = inputValue; | |
| } | |
| setHistory(prev => [...prev, `${previousValue} ${operation} ${inputValue} = ${result}`].slice(-5)); | |
| setDisplay(String(result)); | |
| setPreviousValue(null); | |
| setOperation(null); | |
| setWaitingForOperand(true); | |
| }, [display, operation, previousValue]); | |
| const buttons = [ | |
| { label: 'AC', action: clear, type: 'function' }, | |
| { label: '±', action: toggleSign, type: 'function' }, | |
| { label: '%', action: percentage, type: 'function' }, | |
| { label: '÷', action: () => performOperation('÷'), type: 'operator' }, | |
| { label: '7', action: () => inputDigit('7'), type: 'number' }, | |
| { label: '8', action: () => inputDigit('8'), type: 'number' }, | |
| { label: '9', action: () => inputDigit('9'), type: 'number' }, | |
| { label: '×', action: () => performOperation('×'), type: 'operator' }, | |
| { label: '4', action: () => inputDigit('4'), type: 'number' }, | |
| { label: '5', action: () => inputDigit('5'), type: 'number' }, | |
| { label: '6', action: () => inputDigit('6'), type: 'number' }, | |
| { label: '-', action: () => performOperation('-'), type: 'operator' }, | |
| { label: '1', action: () => inputDigit('1'), type: 'number' }, | |
| { label: '2', action: () => inputDigit('2'), type: 'number' }, | |
| { label: '3', action: () => inputDigit('3'), type: 'number' }, | |
| { label: '+', action: () => performOperation('+'), type: 'operator' }, | |
| { label: '0', action: () => inputDigit('0'), type: 'number', wide: true }, | |
| { label: '.', action: inputDecimal, type: 'number' }, | |
| { label: '=', action: calculate, type: 'equals' }, | |
| ]; | |
| const getButtonClass = (btn) => { | |
| const baseClass = 'h-14 sm:h-16 rounded-2xl font-semibold text-lg sm:text-xl transition-all duration-150 active:scale-95 flex items-center justify-center'; | |
| if (btn.type === 'operator') { | |
| return `${baseClass} bg-gradient-to-br from-orange-500 to-orange-600 text-white shadow-lg shadow-orange-500/30 hover:shadow-orange-500/50 hover:scale-105`; | |
| } | |
| if (btn.type === 'equals') { | |
| return `${baseClass} bg-gradient-to-br from-emerald-500 to-emerald-600 text-white shadow-lg shadow-emerald-500/30 hover:shadow-emerald-500/50 hover:scale-105`; | |
| } | |
| if (btn.type === 'function') { | |
| return `${baseClass} bg-gradient-to-br from-slate-600 to-slate-700 text-white shadow-lg shadow-slate-600/30 hover:shadow-slate-600/50 hover:scale-105`; | |
| } | |
| return `${baseClass} bg-gradient-to-br from-slate-200 to-slate-300 text-slate-800 shadow-lg shadow-slate-400/20 hover:shadow-slate-400/40 hover:scale-105`; | |
| }; | |
| return ( | |
| <div className="min-h-screen flex flex-col items-center justify-center p-4 sm:p-8"> | |
| {/* Header with branding */} | |
| <div className="mb-8 text-center"> | |
| <h1 className="text-3xl sm:text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 via-purple-400 to-pink-400 mb-2"> | |
| Calculator | |
| </h1> | |
| <a | |
| href="https://huggingface.co/spaces/akhaliq/anycoder" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="text-xs sm:text-sm text-slate-400 hover:text-cyan-400 transition-colors" | |
| > | |
| Built with anycoder | |
| </a> | |
| </div> | |
| <div className="w-full max-w-sm animate-scale-in"> | |
| {/* Calculator Body */} | |
| <div className="bg-gradient-to-br from-slate-800 to-slate-900 rounded-3xl p-4 sm:p-6 shadow-2xl shadow-slate-900/50 border border-slate-700/50 backdrop-blur"> | |
| {/* Display Screen */} | |
| <div className="bg-gradient-to-b from-slate-900 to-slate-800 rounded-2xl p-4 sm:p-6 mb-4 shadow-inner border border-slate-700/30"> | |
| <div className="text-right"> | |
| <div className="text-xs sm:text-sm text-slate-500 mb-1 h-4"> | |
| {previousValue} {operation} | |
| </div> | |
| <div className="text-4xl sm:text-5xl font-bold text-white truncate tracking-wider"> | |
| {display} | |
| </div> | |
| </div> | |
| </div> | |
| {/* History Strip */} | |
| {history.length > 0 && ( | |
| <div className="mb-4 px-2"> | |
| <div className="flex gap-1 overflow-x-auto pb-2 scrollbar-hide"> | |
| {history.map((item, index) => ( | |
| <span | |
| key={index} | |
| className="text-xs text-slate-500 whitespace-nowrap bg-slate-800/50 px-2 py-1 rounded-lg" | |
| > | |
| {item} | |
| </span> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| {/* Button Grid */} | |
| <div className="grid grid-cols-4 gap-2 sm:gap-3"> | |
| {buttons.map((btn, index) => ( | |
| <button | |
| key={index} | |
| onClick={btn.action} | |
| className={`${getButtonClass(btn)} ${btn.wide ? 'col-span-2' : ''}`} | |
| > | |
| {btn.label} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Footer */} | |
| <p className="text-center text-slate-500 text-xs mt-6"> | |
| A beautiful calculator built with React & Tailwind | |
| </p> | |
| </div> | |
| </div> | |
| ); | |
| } |