port-calc/index.html

175 lines
7.6 KiB
HTML
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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Калькулятор кассет и портов</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{font:17px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;background:#f0f2f5;color:#0F1218;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px}
.card{background:#fff;border-radius:20px;padding:48px;max-width:520px;width:100%;box-shadow:0 4px 24px rgba(0,0,0,.06)}
h1{font-size:28px;font-weight:800;margin-bottom:8px}
.sub{color:#5B6573;font-size:15px;margin-bottom:24px}
.settings{background:#f6f8fa;border-radius:12px;padding:20px;margin-bottom:24px}
.settings-row{display:flex;gap:12px;margin-bottom:12px}
.settings-row:last-child{margin-bottom:0}
.settings-row label{flex:1;font-size:14px;font-weight:600;color:#5B6573}
.settings-row input{width:100%;padding:10px 14px;font-size:16px;font-weight:600;border:2px solid #d0d5dd;border-radius:8px;outline:none;text-align:center;transition:.15s}
.settings-row input:focus{border-color:#0F1218}
label[for=port]{display:block;font-weight:600;font-size:15px;margin-bottom:8px}
input#port{width:100%;padding:16px 20px;font-size:24px;font-weight:700;border:2px solid #d0d5dd;border-radius:12px;outline:none;transition:.15s;text-align:center}
input#port:focus{border-color:#0F1218}
input#port::placeholder{font-weight:400;color:#9aa3b2;font-size:17px}
button{width:100%;padding:16px;background:#0F1218;color:#fff;border:none;border-radius:12px;font-size:18px;font-weight:700;cursor:pointer;margin-top:16px;transition:.15s}
button:hover{background:#2a2f3a}
button:active{transform:scale(.98)}
.result{padding:24px;background:#f0f2f5;border-radius:12px;margin-top:24px;text-align:center;display:none}
.result.show{display:block}
.result .big{font-size:36px;font-weight:800;color:#0F1218}
.result .big span{color:#0088cc}
.result .detail{font-size:14px;color:#5B6573;margin-top:8px}
.error{color:#e74c3c;font-size:14px;margin-top:8px;display:none}
.error.show{display:block}
.history{margin-top:32px;padding-top:24px;border-top:2px solid #e8eaed;display:none}
.history.show{display:block}
.history h3{font-size:15px;color:#5B6573;font-weight:600;margin-bottom:12px}
.history-item{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;border-radius:8px;cursor:pointer;transition:.1s;font-size:15px}
.history-item:hover{background:#f0f2f5}
.history-item .h-port{font-weight:700}
.history-item .h-result{color:#0088cc;font-weight:600}
.history-item .h-copy{color:#9aa3b2;font-size:13px;cursor:pointer;padding:4px 8px;border-radius:4px}
.history-item .h-copy:hover{background:#d0d5dd;color:#0F1218}
@media(max-width:480px){.card{padding:24px}.settings-row{flex-direction:column;gap:8px}h1{font-size:24px}input#port{font-size:20px}}
</style>
</head>
<body>
<div class="card">
<h1>🔢 Кассеты и порты</h1>
<p class="sub" id="subtitle">84 кассеты × 16 портов = 11344</p>
<div class="settings">
<div class="settings-row">
<label>Кассет <input type="number" id="cassettes" min="1" max="999" onchange="applySettings()"></label>
<label>Портов на кассете <input type="number" id="perPort" min="1" max="999" onchange="applySettings()"></label>
</div>
</div>
<label for="port">Введи номер порта</label>
<input type="number" id="port" min="1" placeholder="например, 699" autofocus>
<div class="error" id="error">Введи число от 1 до 1344</div>
<button onclick="calc()">Рассчитать</button>
<div class="result" id="result">
<div class="big" id="output"></div>
<div class="detail" id="detail"></div>
</div>
<div class="history" id="history">
<h3>📋 История расчётов</h3>
<div id="historyList"></div>
</div>
</div>
<script>
const MAX_HISTORY = 50;
let PORTS_PER_CASSETTE = 16;
let TOTAL_CASSETTES = 84;
let TOTAL_PORTS = TOTAL_CASSETTES * PORTS_PER_CASSETTE;
let history = JSON.parse(localStorage.getItem('portHistory')||'[]');
function loadSettings(){
const c=localStorage.getItem('pcCassettes');
const p=localStorage.getItem('pcPerPort');
if(c)document.getElementById('cassettes').value=TOTAL_CASSETTES=parseInt(c);
if(p)document.getElementById('perPort').value=PORTS_PER_CASSETTE=parseInt(p);
TOTAL_PORTS=TOTAL_CASSETTES*PORTS_PER_CASSETTE;
}
function saveSettings(){
localStorage.setItem('pcCassettes',TOTAL_CASSETTES);
localStorage.setItem('pcPerPort',PORTS_PER_CASSETTE);
}
function updateUI(){
document.getElementById('port').max=TOTAL_PORTS;
document.getElementById('port').placeholder=`1${TOTAL_PORTS}`;
document.getElementById('subtitle').textContent=`${TOTAL_CASSETTES} кассет${TOTAL_CASSETTES%10===1?'а':''} × ${PORTS_PER_CASSETTE} портов = 1${TOTAL_PORTS}`;
}
function applySettings(){
const c=parseInt(document.getElementById('cassettes').value);
const p=parseInt(document.getElementById('perPort').value);
if(!c||c<1)return;
if(!p||p<1)return;
TOTAL_CASSETTES=c;
PORTS_PER_CASSETTE=p;
TOTAL_PORTS=TOTAL_CASSETTES*PORTS_PER_CASSETTE;
saveSettings();
updateUI();
document.getElementById('result').classList.remove('show');
}
function calc(){
const input=document.getElementById('port');
const error=document.getElementById('error');
const result=document.getElementById('result');
const output=document.getElementById('output');
const detail=document.getElementById('detail');
const val=parseInt(input.value);
error.classList.remove('show');
result.classList.remove('show');
if(!val||val<1||val>TOTAL_PORTS){
error.textContent=`Введи число от 1 до ${TOTAL_PORTS}`;
error.classList.add('show');
return;
}
const cassette=Math.floor((val-1)/PORTS_PER_CASSETTE)+1;
const port=((val-1)%PORTS_PER_CASSETTE)+1;
const firstPort=(cassette-1)*PORTS_PER_CASSETTE+1;
const lastPort=cassette*PORTS_PER_CASSETTE;
output.innerHTML=`${cassette} <span>кассета</span> — ${port} <span>порт</span>`;
detail.textContent=`Кассета ${cassette}: порты ${firstPort}${lastPort}`;
result.classList.add('show');
addHistory(val,cassette,port,firstPort,lastPort);
}
function addHistory(portNum,cassette,port,firstPort,lastPort){
const entry={portNum,cassette,port,firstPort,lastPort,time:Date.now()};
history.unshift(entry);
if(history.length>MAX_HISTORY)history=history.slice(0,MAX_HISTORY);
localStorage.setItem('portHistory',JSON.stringify(history));
renderHistory();
}
function renderHistory(){
const el=document.getElementById('history');
const list=document.getElementById('historyList');
if(!history.length){el.classList.remove('show');return}
el.classList.add('show');
list.innerHTML=history.map((h,i)=>`
<div class="history-item" onclick="useHistory(${i})" title="Нажми чтобы вставить номер">
<span class="h-port">${h.portNum}</span>
<span class="h-result">${h.cassette} к — ${h.port} п</span>
<span class="h-copy" onclick="event.stopPropagation();copyResult(${i})" title="Копировать">📋</span>
</div>
`).join('');
}
function useHistory(i){
document.getElementById('port').value=history[i].portNum;
calc();
}
function copyResult(i){
const h=history[i];
const text=`${h.portNum}${h.cassette} кассета — ${h.port} порт`;
navigator.clipboard.writeText(text).catch(()=>{});
}
document.getElementById('port').addEventListener('keydown',e=>{if(e.key==='Enter')calc()});
loadSettings();
updateUI();
renderHistory();
</script>
</body>
</html>