Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 320 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Калькулятор</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
font-family: Arial, Helvetica, sans-serif;
background: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}

.calculator {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
padding: 30px;
width: 100%;
max-width: 500px;
}

h1 {
text-align: center;
color: #333;
margin-bottom: 24px;
font-size: 1.6em;
}

.input-row {
display: flex;
align-items: flex-start;
gap: 10px;
flex-wrap: wrap;
}

.input-group {
flex: 1;
min-width: 100px;
}

.input-group label {
display: block;
font-size: 0.85em;
color: #666;
margin-bottom: 4px;
}

.input-group input {
width: 100%;
padding: 10px 12px;
font-size: 1em;
border: 2px solid #ccc;
border-radius: 8px;
outline: none;
transition: border-color 0.2s;
}

.input-group input:focus {
border-color: #4a90d9;
}

.input-group input.error {
border-color: #e74c3c;
background-color: #fdf0ef;
}

.error-message {
color: #e74c3c;
font-size: 0.78em;
margin-top: 4px;
min-height: 1.2em;
}

.operation-select {
display: flex;
align-items: flex-end;
padding-bottom: 22px;
}

.operation-select select {
padding: 10px 14px;
font-size: 1.1em;
border: 2px solid #ccc;
border-radius: 8px;
background: #fff;
cursor: pointer;
outline: none;
transition: border-color 0.2s;
}

.operation-select select:focus {
border-color: #4a90d9;
}

.calc-button {
display: block;
width: 100%;
padding: 12px;
margin-top: 16px;
font-size: 1.1em;
font-weight: bold;
color: #fff;
background: #4a90d9;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s;
}

.calc-button:hover {
background: #357abd;
}

.calc-button:active {
background: #2c6aab;
}

.result-section {
margin-top: 20px;
padding: 16px;
background: #f7f9fc;
border-radius: 8px;
border: 1px solid #e0e6ed;
}

.result-section h2 {
font-size: 0.9em;
color: #888;
margin-bottom: 8px;
}

.result-current {
font-size: 1.3em;
color: #333;
font-weight: bold;
word-break: break-all;
}

.result-history {
margin-top: 10px;
list-style: none;
}

.result-history li {
font-size: 0.9em;
color: #b0b0b0;
padding: 2px 0;
}

@media (max-width: 480px) {
.input-row {
flex-direction: column;
align-items: stretch;
}

.operation-select {
justify-content: center;
padding-bottom: 0;
margin-bottom: 4px;
}

.calculator {
padding: 20px;
}

h1 {
font-size: 1.3em;
}
}
</style>
</head>
<body>
<div class="calculator">
<h1>Калькулятор</h1>

<div class="input-row">
<div class="input-group">
<label for="num1">Число 1</label>
<input type="text" id="num1" placeholder="Введите число" autocomplete="off">
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type="number"

<div class="error-message" id="error1"></div>
</div>

<div class="operation-select">
<select id="operation">
<option value="+">+</option>
<option value="-">−</option>
<option value="*">×</option>
<option value="/">÷</option>
</select>
</div>

<div class="input-group">
<label for="num2">Число 2</label>
<input type="text" id="num2" placeholder="Введите число" autocomplete="off">
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

и тут

<div class="error-message" id="error2"></div>
</div>
</div>

<button class="calc-button" id="calcBtn">=</button>

<div class="result-section">
<h2>Результат</h2>
<div class="result-current" id="result">—</div>
<ul class="result-history" id="history"></ul>
</div>
</div>

<script>
const num1Input = document.getElementById('num1');
const num2Input = document.getElementById('num2');
const operationSelect = document.getElementById('operation');
const calcBtn = document.getElementById('calcBtn');
const resultDiv = document.getElementById('result');
const historyList = document.getElementById('history');
const error1 = document.getElementById('error1');
const error2 = document.getElementById('error2');
Comment on lines +220 to +227
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Какой-то элемент может быть не найден


const history = [];

function validateInput(input, errorEl) {
const value = input.value.trim();
if (value === '') {
input.classList.add('error');
errorEl.textContent = 'Поле не может быть пустым';
return null;
}

const num = Number(value.replace(',', '.'));
if (isNaN(num)) {
input.classList.add('error');
errorEl.textContent = 'Введите корректное число';
return null;
}

if (!isFinite(num)) {
input.classList.add('error');
errorEl.textContent = 'Число слишком большое';
return null;
}

input.classList.remove('error');
errorEl.textContent = '';
return num;
}

function clearError(input, errorEl) {
input.classList.remove('error');
errorEl.textContent = '';
}

num1Input.addEventListener('input', () => clearError(num1Input, error1));
num2Input.addEventListener('input', () => clearError(num2Input, error2));

function formatNumber(n) {
if (Number.isInteger(n) && Math.abs(n) < 1e15) return n.toString();
const s = n.toPrecision(10);
return parseFloat(s).toString();
}
Comment on lines +265 to +269
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем такая сложность?


function getOperationSymbol(op) {
const symbols = { '+': '+', '-': '−', '*': '×', '/': '÷' };
return symbols[op] || op;
}
Comment on lines +271 to +274
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем......


function calculate() {
const a = validateInput(num1Input, error1);
const b = validateInput(num2Input, error2);

if (a === null || b === null) return;

const op = operationSelect.value;

if (op === '/' && b === 0) {
num2Input.classList.add('error');
error2.textContent = 'Деление на ноль невозможно';
return;
}

let result;
switch (op) {
case '+': result = a + b; break;
case '-': result = a - b; break;
case '*': result = a * b; break;
case '/': result = a / b; break;
}

const expression = `${formatNumber(a)} ${getOperationSymbol(op)} ${formatNumber(b)} = ${formatNumber(result)}`;

resultDiv.textContent = formatNumber(result);

history.unshift(expression);
if (history.length > 10) history.pop();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

длину истории лучше как минимум вынести в константу, а как максимум сделать меньше


historyList.innerHTML = '';
for (let i = 1; i < history.length; i++) {
const li = document.createElement('li');
li.textContent = history[i];
historyList.appendChild(li);
}
}

calcBtn.addEventListener('click', calculate);

document.addEventListener('keydown', (e) => {
if (e.key === 'Enter') calculate();
});
</script>
</body>
</html>