Files
test/public/prototype.html
2026-02-10 16:31:16 +07:00

499 lines
15 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.0" />
<title>Прототип</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;600;700&display=swap');
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
height: 100%;
font-family: 'Manrope', system-ui, sans-serif;
color: #1b1f23;
background: #eef1f4;
}
.app {
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
padding: 14px 12px 16px;
background: #eef1f4;
}
.card {
background: #ffffff;
border-radius: 12px;
border: 1px solid rgba(27, 31, 35, 0.1);
padding: 14px;
box-shadow: 0 8px 18px rgba(27, 31, 35, 0.08);
}
.card.main {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.section-title {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.12em;
color: rgba(27, 31, 35, 0.45);
}
.media-count {
font-size: 12px;
font-weight: 600;
color: rgba(27, 31, 35, 0.7);
}
.media-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
}
.thumb {
position: relative;
height: 64px;
border-radius: 10px;
background-size: cover;
background-position: center;
overflow: hidden;
border: 1px solid rgba(27, 31, 35, 0.08);
}
.thumb::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 0.35));
}
.thumb.video::before {
content: '▶';
position: absolute;
top: 8px;
left: 8px;
width: 20px;
height: 20px;
border-radius: 999px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 10px;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.thumb span {
position: absolute;
bottom: 6px;
left: 6px;
font-size: 10px;
font-weight: 600;
color: #fff;
z-index: 1;
}
.analysis {
display: grid;
gap: 10px;
margin-top: 6px;
}
.loader {
height: 8px;
background: rgba(15, 76, 129, 0.12);
border-radius: 999px;
overflow: hidden;
}
.loader__bar {
height: 100%;
width: 0;
background: linear-gradient(90deg, #0f4c81, #4f8fc7);
border-radius: inherit;
transition: width 0.4s ease;
}
.hint {
font-size: 11px;
color: rgba(27, 31, 35, 0.55);
}
.table {
width: 100%;
border-collapse: collapse;
font-size: 11px;
}
.table th,
.table td {
padding: 6px 6px;
text-align: left;
border-bottom: 1px solid rgba(27, 31, 35, 0.08);
}
.table th {
color: rgba(27, 31, 35, 0.55);
font-weight: 600;
}
.total {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
border-radius: 10px;
background: #f0f2f4;
font-size: 12px;
font-weight: 700;
}
.q {
display: inline-flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
margin-left: 4px;
border-radius: 999px;
background: rgba(15, 76, 129, 0.12);
color: #0f4c81;
font-size: 10px;
font-weight: 700;
}
.accept-card {
display: grid;
grid-template-columns: 54px 1fr;
gap: 10px;
align-items: center;
padding: 10px;
border-radius: 12px;
background: #f0f2f4;
}
.accept-photo {
width: 54px;
height: 54px;
border-radius: 10px;
background-size: cover;
background-position: center;
border: 1px solid rgba(27, 31, 35, 0.08);
}
.accept-title {
font-size: 12px;
font-weight: 600;
}
.accept-meta {
font-size: 11px;
color: rgba(27, 31, 35, 0.6);
}
.tag {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: 999px;
font-size: 10px;
font-weight: 600;
}
.tag.success {
background: rgba(31, 129, 84, 0.14);
color: #1f8154;
}
.tag.pending {
background: rgba(211, 135, 32, 0.15);
color: #b7741c;
}
.tag.info {
background: rgba(26, 77, 122, 0.14);
color: #1a4d7a;
}
.toggle-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
padding: 8px 10px;
border-radius: 10px;
background: #f0f2f4;
font-size: 12px;
font-weight: 600;
}
.switch {
position: relative;
width: 42px;
height: 22px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
inset: 0;
background-color: #c7ced6;
transition: 0.2s;
border-radius: 999px;
}
.slider:before {
position: absolute;
content: '';
height: 18px;
width: 18px;
left: 2px;
top: 2px;
background-color: white;
transition: 0.2s;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.switch input:checked + .slider {
background-color: #0f4c81;
}
.switch input:checked + .slider:before {
transform: translateX(20px);
}
.list {
display: grid;
gap: 8px;
margin-top: 8px;
}
.item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
border-radius: 10px;
background: #f0f2f4;
font-size: 12px;
}
.action {
border: none;
border-radius: 12px;
padding: 12px 14px;
font-size: 18px;
font-weight: 700;
cursor: pointer;
background: #0f4c81;
color: #fff;
box-shadow: 0 10px 20px rgba(15, 76, 129, 0.25);
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}
.action:active {
transform: scale(0.98);
}
.action[disabled] {
opacity: 0.5;
cursor: not-allowed;
box-shadow: none;
transform: none;
}
</style>
</head>
<body>
<div class="app">
<div class="card main">
<div id="screenContent"></div>
</div>
<button class="action" id="actionButton" aria-label="Дальше"></button>
</div>
<script>
(function () {
var state = {
screen: 0,
loadingTimer: null,
loadingProgress: 0,
accepted: false
};
var screens = [
{
content: function () {
return (
'<div class="section-title">Материалы</div>' +
'<div class="media-count">8 фото · 2 видео</div>' +
'<div class="media-grid">' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1502005097973-6a7082348e28?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1502005097973-6a7082348e28?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div class="thumb video" style="background-image:url(https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=600&q=60)"><span>Видео</span></div>' +
'<div class="thumb video" style="background-image:url(https://images.unsplash.com/photo-1502005097973-6a7082348e28?auto=format&fit=crop&w=600&q=60)"><span>Видео</span></div>' +
'<div class="thumb" style="background-image:url(https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=600&q=60)"></div>' +
'</div>'
);
},
onEnter: function () {},
onAction: function () {
state.screen = 1;
render();
}
},
{
content: function () {
return (
'<div class="section-title">Анализ</div>' +
'<div class="analysis">' +
'<div class="loader"><div class="loader__bar" id="loaderBar"></div></div>' +
'<div class="hint">5 секунд</div>' +
'</div>'
);
},
onEnter: function () {
var bar = document.getElementById('loaderBar');
state.loadingProgress = 0;
if (state.loadingTimer) {
clearInterval(state.loadingTimer);
}
state.loadingTimer = setInterval(function () {
state.loadingProgress += 20;
if (bar) {
bar.style.width = state.loadingProgress + '%';
}
if (state.loadingProgress >= 100) {
clearInterval(state.loadingTimer);
state.loadingTimer = null;
state.screen = 2;
render();
}
}, 1000);
},
onAction: function () {}
},
{
content: function () {
return (
'<table class="table">' +
'<thead><tr><th>Работы</th><th>Старт</th><th>Финиш</th><th>Сумма</th></tr></thead>' +
'<tbody>' +
'<tr><td>Демонтаж<span class="q" title="Стены чистые, мусор вывезен">?</span></td><td>12.03</td><td>15.03</td><td>120 000 ₽</td></tr>' +
'<tr><td>Черновые работы<span class="q" title="Геометрия в допуске">?</span></td><td>16.03</td><td>24.03</td><td>340 000 ₽</td></tr>' +
'<tr><td>Электрика<span class="q" title="Маркировка и линии">?</span></td><td>25.03</td><td>28.03</td><td>180 000 ₽</td></tr>' +
'<tr><td>Чистовая отделка<span class="q" title="Без дефектов">?</span></td><td>29.03</td><td>08.04</td><td>410 000 ₽</td></tr>' +
'</tbody>' +
'</table>' +
'<div class="section-title" style="margin-top:8px;">Материалы</div>' +
'<table class="table">' +
'<thead><tr><th>Позиция</th><th>Объём</th><th>Сумма</th></tr></thead>' +
'<tbody>' +
'<tr><td>Штукатурка</td><td>120 м²</td><td>94 000 ₽</td></tr>' +
'<tr><td>Кабель</td><td>320 м</td><td>52 000 ₽</td></tr>' +
'<tr><td>Плитка</td><td>34 м²</td><td>126 000 ₽</td></tr>' +
'<tr><td>Смеси</td><td>48 меш.</td><td>37 000 ₽</td></tr>' +
'</tbody>' +
'</table>' +
'<div class="total" style="margin-top:8px;"><span>Итого</span><span>1 359 000 ₽</span></div>'
);
},
onEnter: function () {},
onAction: function () {
state.screen = 3;
render();
}
},
{
content: function () {
var statusTag = state.accepted ? '<span class="tag success">Принято</span>' : '<span class="tag pending">Ожидает</span>';
var payTag = state.accepted ? '<span class="tag success">Переводится</span>' : '<span class="tag pending">Ожидает</span>';
return (
'<div class="section-title">Приемка</div>' +
'<div class="accept-card">' +
'<div class="accept-photo" style="background-image:url(https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=600&q=60)"></div>' +
'<div>' +
'<div class="accept-title">Черновые работы</div>' +
'<div class="accept-meta">Эксперт подтвердил · Смирнов А.</div>' +
'<div class="tag info" style="margin-top:6px;">Фото-отчет загружен</div>' +
'</div>' +
'</div>' +
'<div class="toggle-row">' +
'<span>Подтвердить приемку</span>' +
'<label class="switch">' +
'<input type="checkbox" id="acceptToggle" ' + (state.accepted ? 'checked' : '') + ' />' +
'<span class="slider"></span>' +
'</label>' +
'</div>' +
'<div class="list">' +
'<div class="item"><strong>Статус</strong>' + statusTag + '</div>' +
'<div class="item"><strong>Оплата</strong>' + payTag + '</div>' +
'</div>'
);
},
onEnter: function () {
var toggle = document.getElementById('acceptToggle');
if (toggle) {
toggle.addEventListener('change', function (event) {
state.accepted = event.target.checked;
render();
});
}
},
onAction: function () {
state.screen = 0;
state.accepted = false;
render();
}
}
];
var screenContent = document.getElementById('screenContent');
var actionButton = document.getElementById('actionButton');
function render() {
var screen = screens[state.screen];
screenContent.innerHTML = screen.content();
actionButton.disabled = state.screen === 1;
if (screen.onEnter) {
screen.onEnter();
}
}
actionButton.addEventListener('click', function () {
var screen = screens[state.screen];
if (screen.onAction) {
screen.onAction();
}
});
render();
})();
</script>
</body>
</html>