windows/components/Calculator.vue

263 lines
6.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { ref, computed } from 'vue';
// Calculator state
const display = ref('0');
const previousValue = ref<number | null>(null);
const operation = ref<string | null>(null);
const waitingForNewValue = ref(false);
// Calculator logic
function inputNumber(num: string) {
if (waitingForNewValue.value) {
display.value = num;
waitingForNewValue.value = false;
} else {
display.value = display.value === '0' ? num : display.value + num;
}
}
function inputDecimal() {
if (waitingForNewValue.value) {
display.value = '0.';
waitingForNewValue.value = false;
} else if (display.value.indexOf('.') === -1) {
display.value += '.';
}
}
function clear() {
display.value = '0';
previousValue.value = null;
operation.value = null;
waitingForNewValue.value = false;
}
function performOperation(nextOperation: string) {
const inputValue = parseFloat(display.value);
if (previousValue.value === null) {
previousValue.value = inputValue;
} else if (operation.value) {
const currentValue = previousValue.value || 0;
const newValue = calculate(currentValue, inputValue, operation.value);
display.value = String(newValue);
previousValue.value = newValue;
}
waitingForNewValue.value = true;
operation.value = nextOperation;
}
function calculate(firstValue: number, secondValue: number, operation: string): number {
switch (operation) {
case '+': return firstValue + secondValue;
case '-': return firstValue - secondValue;
case '×': return firstValue * secondValue;
case '÷': return secondValue !== 0 ? firstValue / secondValue : 0;
default: return secondValue;
}
}
function equals() {
const inputValue = parseFloat(display.value);
if (previousValue.value !== null && operation.value) {
const newValue = calculate(previousValue.value, inputValue, operation.value);
display.value = String(newValue);
previousValue.value = null;
operation.value = null;
waitingForNewValue.value = true;
}
}
// Format display value
const formattedDisplay = computed(() => {
const value = parseFloat(display.value);
if (isNaN(value)) return '0';
// Handle very large or very small numbers
if (Math.abs(value) > 999999999 || (Math.abs(value) < 0.000001 && value !== 0)) {
return value.toExponential(6);
}
// Format with appropriate decimal places
return value.toLocaleString('en-US', {
maximumFractionDigits: 8,
minimumFractionDigits: 0
});
});
</script>
<template>
<div class="calculator">
<div class="display">
<div class="display-value">{{ formattedDisplay }}</div>
</div>
<div class="buttons">
<!-- Row 1 -->
<button @click="clear" class="btn btn-function">C</button>
<button @click="clear" class="btn btn-function">CE</button>
<button @click="performOperation('÷')" class="btn btn-operator">÷</button>
<button @click="performOperation('×')" class="btn btn-operator">×</button>
<!-- Row 2 -->
<button @click="inputNumber('7')" class="btn btn-number">7</button>
<button @click="inputNumber('8')" class="btn btn-number">8</button>
<button @click="inputNumber('9')" class="btn btn-number">9</button>
<button @click="performOperation('-')" class="btn btn-operator"></button>
<!-- Row 3 -->
<button @click="inputNumber('4')" class="btn btn-number">4</button>
<button @click="inputNumber('5')" class="btn btn-number">5</button>
<button @click="inputNumber('6')" class="btn btn-number">6</button>
<button @click="performOperation('+')" class="btn btn-operator">+</button>
<!-- Row 4 -->
<button @click="inputNumber('1')" class="btn btn-number">1</button>
<button @click="inputNumber('2')" class="btn btn-number">2</button>
<button @click="inputNumber('3')" class="btn btn-number">3</button>
<button @click="equals" class="btn btn-equals" rowspan="2">=</button>
<!-- Row 5 -->
<button @click="inputNumber('0')" class="btn btn-number btn-zero">0</button>
<button @click="inputDecimal" class="btn btn-number">.</button>
</div>
</div>
</template>
<style scoped>
.calculator {
width: 100%;
height: 100%;
background: var(--window-background);
display: flex;
flex-direction: column;
padding: 16px;
box-sizing: border-box;
}
.display {
background: #1a1a1a;
border: 2px solid #333;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
min-height: 60px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.display-value {
color: #00ff00;
font-family: 'Courier New', monospace;
font-size: 24px;
font-weight: bold;
text-align: right;
word-break: break-all;
line-height: 1.2;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
flex: 1;
}
.btn {
border: none;
border-radius: 8px;
font-size: 18px;
font-weight: bold;
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: center;
justify-content: center;
min-height: 50px;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.btn-number {
background: #4a4a4a;
color: white;
}
.btn-number:hover {
background: #5a5a5a;
}
.btn-operator {
background: #ff9500;
color: white;
}
.btn-operator:hover {
background: #ffad33;
}
.btn-function {
background: #a6a6a6;
color: black;
}
.btn-function:hover {
background: #b6b6b6;
}
.btn-equals {
background: #ff9500;
color: white;
grid-row: span 2;
}
.btn-equals:hover {
background: #ffad33;
}
.btn-zero {
grid-column: span 2;
}
/* Dark theme adjustments */
.theme-light .display {
background: #f0f0f0;
border-color: #ccc;
}
.theme-light .display-value {
color: #333;
}
.theme-light .btn-number {
background: #e0e0e0;
color: #333;
}
.theme-light .btn-number:hover {
background: #d0d0d0;
}
.theme-light .btn-function {
background: #c0c0c0;
color: #333;
}
.theme-light .btn-function:hover {
background: #b0b0b0;
}
</style>