JXCT Soil Sensor 7-in-1
v3.4.9 (June 2025)
Professional IoT soil monitoring system with ESP32, Modbus RTU, MQTT, and advanced compensation algorithms
Загрузка...
Поиск...
Не найдено
jxct_ui_system.cpp
См. документацию.
1
#include "
jxct_ui_system.h
"
2
3
// 🎨 ЕДИНЫЙ CSS ДЛЯ ВСЕХ СТРАНИЦ
4
const
char
*
getUnifiedCSS
()
5
{
6
static
const
char
css[] = R
"(
7
/* === JXCT UI DESIGN SYSTEM v2.3.1 === */
8
* { box-sizing: border-box; }
9
10
body {
11
font-family: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
12
margin: 0;
13
padding: 20px;
14
background: #f5f5f5;
15
color: #333;
16
font-size: 16px;
17
line-height: 1.5;
18
}
19
20
.container {
21
max-width: 1000px;
22
margin: 0 auto;
23
background: white;
24
border-radius: 6px;
25
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
26
padding: 30px;
27
}
28
29
/* === ТИПОГРАФИКА === */
30
h1 {
31
color: #333;
32
font-size: 22px;
33
margin: 0 0 20px 0;
34
font-weight: 600;
35
}
36
37
h2 {
38
color: #333;
39
font-size: 18px;
40
margin: 20px 0 12px 0;
41
font-weight: 500;
42
border-bottom: 2px solid #4CAF50;
43
padding-bottom: 6px;
44
}
45
46
/* === НАВИГАЦИЯ === */
47
.nav {
48
margin-bottom: 30px;
49
padding: 15px 0;
50
border-bottom: 1px solid #ddd;
51
}
52
53
.nav a {
54
display: inline-block;
55
margin-right: 10px;
56
text-decoration: none;
57
color: #4CAF50;
58
font-weight: 600;
59
padding: 8px 12px;
60
border-radius: 6px;
61
transition: 0.2s ease;
62
}
63
64
.nav a:hover {
65
background: #4CAF50;
66
color: white;
67
transform: translateY(-1px);
68
}
69
70
/* === СЕКЦИИ === */
71
.section {
72
margin-bottom: 25px;
73
padding: 15px;
74
border: 1px solid #ddd;
75
border-radius: 6px;
76
background: #fafafa;
77
}
78
79
/* === ФОРМЫ === */
80
.form-group {
81
margin-bottom: 20px;
82
}
83
84
label {
85
display: block;
86
margin-bottom: 6px;
87
font-weight: 600;
88
color: #333;
89
}
90
91
input[type=text], input[type=password], input[type=number], input[type=email], input[type=file], select, textarea {
92
width: 100%;
93
padding: 10px;
94
border: 2px solid #ddd;
95
border-radius: 6px;
96
font-size: 16px;
97
transition: 0.2s ease;
98
}
99
100
input:focus, select:focus, textarea:focus {
101
outline: none;
102
border-color: #4CAF50;
103
box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.1);
104
}
105
106
/* === КНОПКИ (ЕДИНАЯ СИСТЕМА) === */
107
.btn {
108
display: inline-block;
109
padding: 8px 16px;
110
border: none;
111
border-radius: 6px;
112
font-size: 14px;
113
font-weight: 500;
114
cursor: pointer;
115
text-decoration: none;
116
transition: 0.3s ease;
117
margin-right: 10px;
118
margin-bottom: 10px;
119
min-width: 120px;
120
text-align: center;
121
}
122
123
.btn:hover {
124
transform: translateY(-2px);
125
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
126
}
127
128
.btn-primary {
129
background: #4CAF50;
130
color: white;
131
}
132
133
.btn-primary:hover {
134
background: #45a049;
135
}
136
137
.btn-secondary {
138
background: #2196F3;
139
color: white;
140
}
141
142
.btn-secondary:hover {
143
background: #0b7dda;
144
}
145
146
.btn-danger {
147
background: #F44336;
148
color: white;
149
}
150
151
.btn-danger:hover {
152
background: #d32f2f;
153
}
154
155
.btn-outline {
156
background: transparent;
157
color: #4CAF50;
158
border: 2px solid #4CAF50;
159
}
160
161
.btn-outline:hover {
162
background: #4CAF50;
163
color: white;
164
}
165
166
/* === СООБЩЕНИЯ === */
167
.msg {
168
padding: 15px 20px;
169
margin-bottom: 20px;
170
border-radius: 6px;
171
font-weight: 500;
172
border-left: 4px solid;
173
}
174
175
.msg-success {
176
background: #e8f5e8;
177
color: #2e7d32;
178
border-left-color: #4CAF50;
179
}
180
181
.msg-error {
182
background: #ffebee;
183
color: #c62828;
184
border-left-color: #F44336;
185
}
186
187
.msg-warning {
188
background: #fff8e1;
189
color: #f57c00;
190
border-left-color: #FFC107;
191
}
192
193
.msg-info {
194
background: #e3f2fd;
195
color: #1565c0;
196
border-left-color: #2196F3;
197
}
198
199
/* === ВСПОМОГАТЕЛЬНЫЕ ЭЛЕМЕНТЫ === */
200
.help {
201
color: #666;
202
font-size: 14px;
203
margin-top: 5px;
204
font-style: italic;
205
}
206
207
.status-dot {
208
display: inline-block;
209
width: 12px;
210
height: 12px;
211
border-radius: 50%;
212
margin-right: 8px;
213
vertical-align: middle;
214
}
215
216
.dot-ok { background: #4CAF50; }
217
.dot-warn { background: #FFC107; }
218
.dot-err { background: #F44336; }
219
.dot-off { background: #bbb; }
220
221
/* === ЛОАДЕР === */
222
.loader {
223
border: 3px solid #f3f3f3;
224
border-top: 3px solid #4CAF50;
225
border-radius: 50%;
226
width: 20px;
227
height: 20px;
228
animation: spin 1s linear infinite;
229
display: inline-block;
230
margin-right: 10px;
231
}
232
233
@keyframes spin {
234
0% { transform: rotate(0deg); }
235
100% { transform: rotate(360deg); }
236
}
237
238
/* === TOAST УВЕДОМЛЕНИЯ === */
239
.toast {
240
position: fixed;
241
top: 20px;
242
right: 20px;
243
padding: 15px 25px;
244
border-radius: 6px;
245
color: white;
246
font-weight: 600;
247
z-index: 9999;
248
opacity: 0;
249
transform: translateX(100%);
250
transition: all 0.3s ease;
251
}
252
253
.toast.show {
254
opacity: 1;
255
transform: translateX(0);
256
}
257
258
259
260
/* === МОБИЛЬНАЯ АДАПТАЦИЯ === */
261
@media (max-width: 768px) {
262
body { padding: 10px; }
263
.container { padding: 20px; margin: 5px; }
264
h1 { font-size: 20px; }
265
h2 { font-size: 16px; }
266
.nav a {
267
display: block;
268
margin: 5px 0;
269
text-align: center;
270
}
271
.btn {
272
width: 100%;
273
margin-right: 0;
274
margin-bottom: 15px;
275
}
276
.section { padding: 12px; }
277
.form-group { margin-bottom: 15px; }
278
279
280
}
281
)";
282
return
css;
283
}
284
285
// 🎯 ГЕНЕРАЦИЯ HTML КНОПОК
286
String
generateButton
(
ButtonType
type,
const
char
* icon,
const
char
* text,
const
char
* action)
287
{
288
String cssClass =
"btn "
;
289
290
switch
(type)
291
{
292
case
ButtonType::PRIMARY
:
293
cssClass +=
"btn-primary"
;
294
break
;
295
case
ButtonType::SECONDARY
:
296
cssClass +=
"btn-secondary"
;
297
break
;
298
case
ButtonType::DANGER
:
299
cssClass +=
"btn-danger"
;
300
break
;
301
case
ButtonType::SUCCESS
:
302
cssClass +=
"btn-primary"
;
303
break
;
304
case
ButtonType::OUTLINE
:
305
cssClass +=
"btn-outline"
;
306
break
;
307
}
308
309
String html =
"<button type='submit' class='"
+ cssClass +
"'"
;
310
if
(strlen(action) > 0)
311
{
312
html =
"<button type='button' class='"
+ cssClass +
"' onclick=\""
+ String(action) +
"\""
;
313
}
314
html +=
">"
+ String(icon) +
" "
+ String(text) +
"</button>"
;
315
316
return
html;
317
}
318
319
// 🍞 TOAST УВЕДОМЛЕНИЯ
320
const
char
*
getToastHTML
()
321
{
322
return
R
"(
323
<script>
324
function showToast(message, type) {
325
const toast = document.createElement('div');
326
toast.className = 'toast';
327
toast.textContent = message;
328
329
const colors = {
330
'success': '#4CAF50',
331
'error': '#F44336',
332
'warning': '#FFC107',
333
'info': '#2196F3'
334
};
335
336
toast.style.background = colors[type] || colors['info'];
337
document.body.appendChild(toast);
338
339
setTimeout(() => toast.classList.add('show'), 100);
340
setTimeout(() => {
341
toast.classList.remove('show');
342
setTimeout(() => document.body.removeChild(toast), 300);
343
}, 3000);
344
}
345
346
// Показать toast при загрузке если есть сообщение
347
window.addEventListener('load', function() {
348
const urlParams = new URLSearchParams(window.location.search);
349
const msg = urlParams.get('msg');
350
const type = urlParams.get('type') || 'info';
351
if (msg) {
352
showToast(decodeURIComponent(msg), type);
353
}
354
});
355
</script>
356
)";
357
}
358
359
// ⌛ ЛОАДЕР
360
const
char
*
getLoaderHTML
()
361
{
362
return
"<div class='loader'></div>"
;
363
}
getUnifiedCSS
const char * getUnifiedCSS()
Определения
jxct_ui_system.cpp:4
getLoaderHTML
const char * getLoaderHTML()
Определения
jxct_ui_system.cpp:360
generateButton
String generateButton(ButtonType type, const char *icon, const char *text, const char *action)
Определения
jxct_ui_system.cpp:286
getToastHTML
const char * getToastHTML()
Определения
jxct_ui_system.cpp:320
jxct_ui_system.h
ButtonType
ButtonType
Определения
jxct_ui_system.h:64
ButtonType::SECONDARY
@ SECONDARY
Определения
jxct_ui_system.h:66
ButtonType::PRIMARY
@ PRIMARY
Определения
jxct_ui_system.h:65
ButtonType::OUTLINE
@ OUTLINE
Определения
jxct_ui_system.h:69
ButtonType::DANGER
@ DANGER
Определения
jxct_ui_system.h:67
ButtonType::SUCCESS
@ SUCCESS
Определения
jxct_ui_system.h:68
src
jxct_ui_system.cpp
Документация по JXCT Soil Sensor 7-in-1. Последние изменения: Ср 25 Июн 2025 01:11:47. Создано системой
1.13.2