windows/components/Calculator.vue

267 lines
6.2 KiB
Vue
Raw Normal View History

2025-09-25 05:38:59 +00:00
<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;
2025-09-25 06:38:14 +00:00
padding: 20px;
2025-09-25 05:38:59 +00:00
box-sizing: border-box;
2025-09-25 06:38:14 +00:00
min-height: 400px; /* Ensure minimum height for all buttons */
2025-09-25 05:38:59 +00:00
}
.display {
background: #1a1a1a;
border: 2px solid #333;
border-radius: 8px;
padding: 16px;
margin-bottom: 16px;
2025-09-25 06:38:14 +00:00
min-height: 55px;
2025-09-25 05:38:59 +00:00
display: flex;
align-items: center;
justify-content: flex-end;
2025-09-25 06:38:14 +00:00
flex-shrink: 0; /* Prevent display from shrinking */
2025-09-25 05:38:59 +00:00
}
.display-value {
color: #00ff00;
font-family: 'Courier New', monospace;
2025-09-25 06:38:14 +00:00
font-size: 20px;
2025-09-25 05:38:59 +00:00
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;
2025-09-25 06:38:14 +00:00
min-height: 300px; /* Ensure enough space for all button rows */
2025-09-25 05:38:59 +00:00
}
.btn {
border: none;
border-radius: 8px;
2025-09-25 06:38:14 +00:00
font-size: 16px;
2025-09-25 05:38:59 +00:00
font-weight: bold;
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: center;
justify-content: center;
2025-09-25 06:38:14 +00:00
min-height: 48px;
max-height: 65px;
2025-09-25 05:38:59 +00:00
}
.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>