Kgshop commited on
Commit
77b4bcf
·
verified ·
1 Parent(s): a245efb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +303 -263
app.py CHANGED
@@ -17,9 +17,6 @@ REPO_ID = "Kgshop/clients"
17
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
18
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
19
 
20
- # Ссылка на логотип
21
- LOGO_URL = "https://cdn-avatars.huggingface.co/v1/production/uploads/67b22aaeae9b6a59f1cfb849/NQvBksXzJItYt6hfFjyaB.jpeg"
22
-
23
  # Настройка логирования
24
  logging.basicConfig(level=logging.DEBUG)
25
 
@@ -105,9 +102,9 @@ def catalog():
105
  <head>
106
  <meta charset="UTF-8">
107
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
108
- <title>Канцтовары оптом и в розницу</title>
109
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
110
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
111
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
112
  <style>
113
  * {
@@ -116,19 +113,19 @@ def catalog():
116
  box-sizing: border-box;
117
  }
118
  body {
119
- font-family: 'Poppins', sans-serif;
120
- background: linear-gradient(135deg, #f0f2f5, #e9ecef);
121
- color: #2d3748;
122
  line-height: 1.6;
123
  transition: background 0.3s, color 0.3s;
124
- padding-bottom: 60px; /* Для навигационной панели */
125
  }
126
  body.dark-mode {
127
- background: linear-gradient(135deg, #1a202c, #2d3748);
128
- color: #e2e8f0;
129
  }
130
  .container {
131
- max-width: 1300px;
132
  margin: 0 auto;
133
  padding: 20px;
134
  }
@@ -137,36 +134,30 @@ def catalog():
137
  justify-content: space-between;
138
  align-items: center;
139
  padding: 15px 0;
140
- border-bottom: 1px solid #e2e8f0;
141
- }
142
- .header-logo {
143
- width: 60px;
144
- height: 60px;
145
- border-radius: 50%;
146
- object-fit: cover;
147
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
148
- transition: transform 0.3s ease, box-shadow 0.3s ease;
149
- }
150
- .header-logo:hover {
151
- transform: scale(1.1);
152
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
153
  }
154
  .header h1 {
155
- font-size: 1.5rem;
156
- font-weight: 600;
157
- margin-left: 15px;
 
 
 
158
  }
159
  .theme-toggle {
160
  background: none;
161
  border: none;
162
  font-size: 1.5rem;
163
  cursor: pointer;
164
- color: #4a5568;
165
  transition: color 0.3s ease;
166
  }
167
  .theme-toggle:hover {
168
  color: #526df2;
169
  }
 
 
 
170
  .filters-container {
171
  margin: 20px 0;
172
  display: flex;
@@ -183,8 +174,8 @@ def catalog():
183
  max-width: 600px;
184
  padding: 12px 18px;
185
  font-size: 1rem;
186
- border: 1px solid #e2e8f0;
187
- border-radius: 8px;
188
  outline: none;
189
  box-shadow: 0 2px 5px rgba(0,0,0,0.05);
190
  transition: all 0.3s ease;
@@ -194,14 +185,14 @@ def catalog():
194
  box-shadow: 0 4px 15px rgba(82, 109, 242, 0.2);
195
  }
196
  .category-filter {
197
- padding: 8px 16px;
198
- border: 1px solid #e2e8f0;
199
- border-radius: 8px;
200
  background-color: #fff;
201
  cursor: pointer;
202
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
203
  font-size: 0.9rem;
204
- font-weight: 400;
205
  }
206
  .category-filter.active, .category-filter:hover {
207
  background-color: #526df2;
@@ -209,27 +200,41 @@ def catalog():
209
  border-color: #526df2;
210
  box-shadow: 0 2px 10px rgba(82, 109, 242, 0.3);
211
  }
 
 
 
 
 
212
  .products-grid {
213
  display: grid;
214
- grid-template-columns: repeat(2, minmax(200px, 1fr));
215
- gap: 15px;
216
  padding: 10px;
217
  }
218
  .product {
219
- background: #fff;
 
220
  border-radius: 15px;
221
  padding: 15px;
222
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
223
- transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
 
 
224
  overflow: hidden;
225
  }
 
 
 
 
 
226
  body.dark-mode .product {
227
- background: #2d3748;
228
- color: #fff;
 
229
  }
230
- .product:hover {
231
- transform: translateY(-5px) scale(1.02);
232
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
233
  }
234
  .product-image {
235
  width: 100%;
@@ -240,6 +245,10 @@ def catalog():
240
  display: flex;
241
  justify-content: center;
242
  align-items: center;
 
 
 
 
243
  }
244
  .product-image img {
245
  max-width: 100%;
@@ -248,11 +257,11 @@ def catalog():
248
  transition: transform 0.3s ease;
249
  }
250
  .product-image img:hover {
251
- transform: scale(1.1);
252
  }
253
  .product h2 {
254
- font-size: 1rem;
255
- font-weight: 600;
256
  margin: 10px 0;
257
  text-align: center;
258
  white-space: nowrap;
@@ -260,15 +269,22 @@ def catalog():
260
  text-overflow: ellipsis;
261
  }
262
  .product-price {
263
- font-size: 1.1rem;
264
- color: #ef4444;
265
  font-weight: 700;
266
  text-align: center;
267
  margin: 5px 0;
268
  }
 
 
 
 
 
 
 
269
  .product-description {
270
- font-size: 0.8rem;
271
- color: #718096;
272
  text-align: center;
273
  margin-bottom: 15px;
274
  overflow: hidden;
@@ -276,17 +292,17 @@ def catalog():
276
  white-space: nowrap;
277
  }
278
  body.dark-mode .product-description {
279
- color: #a0aec0;
280
  }
281
  .product-button {
282
  display: block;
283
  width: 100%;
284
- padding: 8px;
285
  border: none;
286
- border-radius: 8px;
287
  background-color: #526df2;
288
  color: white;
289
- font-size: 0.8rem;
290
  font-weight: 500;
291
  cursor: pointer;
292
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -300,29 +316,32 @@ def catalog():
300
  transform: translateY(-2px);
301
  }
302
  .add-to-cart {
303
- background-color: #10b981;
304
  }
305
  .add-to-cart:hover {
306
- background-color: #059669;
307
- box-shadow: 0 4px 15px rgba(5, 150, 105, 0.4);
308
  }
309
  #cart-button {
310
  position: fixed;
311
  bottom: 80px;
312
  right: 20px;
313
- background-color: #ef4444;
314
  color: white;
315
  border: none;
316
  border-radius: 50%;
317
- width: 50px;
318
- height: 50px;
319
- font-size: 1.2rem;
320
  cursor: pointer;
321
  display: none;
322
- box-shadow: 0 4px 15px rgba(239, 68, 68, 0.4);
323
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
324
  z-index: 1000;
325
  }
 
 
 
326
  .modal {
327
  display: none;
328
  position: fixed;
@@ -345,8 +364,8 @@ def catalog():
345
  animation: slideIn 0.3s ease-out;
346
  }
347
  body.dark-mode .modal-content {
348
- background: #2d3748;
349
- color: #e2e8f0;
350
  }
351
  @keyframes slideIn {
352
  from { transform: translateY(-50px); opacity: 0; }
@@ -355,15 +374,15 @@ def catalog():
355
  .close {
356
  float: right;
357
  font-size: 1.5rem;
358
- color: #718096;
359
  cursor: pointer;
360
  transition: color 0.3s;
361
  }
362
  .close:hover {
363
- color: #2d3748;
364
  }
365
  body.dark-mode .close {
366
- color: #a0aec0;
367
  }
368
  body.dark-mode .close:hover {
369
  color: #fff;
@@ -373,10 +392,10 @@ def catalog():
373
  justify-content: space-between;
374
  align-items: center;
375
  padding: 15px 0;
376
- border-bottom: 1px solid #e2e8f0;
377
  }
378
  body.dark-mode .cart-item {
379
- border-bottom: 1px solid #4a5568;
380
  }
381
  .cart-item img {
382
  width: 50px;
@@ -389,24 +408,24 @@ def catalog():
389
  width: 100%;
390
  max-width: 150px;
391
  padding: 8px;
392
- border: 1px solid #e2e8f0;
393
  border-radius: 8px;
394
  font-size: 1rem;
395
  margin: 5px 0;
396
  }
397
  .clear-cart {
398
- background-color: #ef4444;
399
  }
400
  .clear-cart:hover {
401
- background-color: #dc2626;
402
- box-shadow: 0 4px 15px rgba(220, 38, 38, 0.4);
403
  }
404
  .order-button {
405
- background-color: #10b981;
406
  }
407
  .order-button:hover {
408
- background-color: #059669;
409
- box-shadow: 0 4px 15px rgba(5, 150, 105, 0.4);
410
  }
411
  .navbar {
412
  position: fixed;
@@ -421,11 +440,11 @@ def catalog():
421
  z-index: 1000;
422
  }
423
  body.dark-mode .navbar {
424
- background-color: #2d3748;
425
  }
426
  .navbar a {
427
  text-align: center;
428
- color: #4a5568;
429
  text-decoration: none;
430
  font-size: 0.9rem;
431
  transition: color 0.3s ease;
@@ -439,18 +458,28 @@ def catalog():
439
  margin-bottom: 5px;
440
  }
441
  body.dark-mode .navbar a {
442
- color: #a0aec0;
443
  }
444
  .navbar a:hover {
445
  color: #526df2;
446
  }
 
 
 
 
 
 
 
 
 
 
 
447
  </style>
448
  </head>
449
  <body>
450
  <div class="container">
451
  <div class="header">
452
- <img src="''' + LOGO_URL + '''" alt="Logo" class="header-logo">
453
- <h1>Каталог</h1>
454
  <button class="theme-toggle" onclick="toggleTheme()">
455
  <i class="fas fa-moon"></i>
456
  </button>
@@ -467,6 +496,7 @@ def catalog():
467
  <div class="products-grid" id="products-grid">
468
  {% for product in products %}
469
  <div class="product"
 
470
  data-name="{{ product['name']|lower }}"
471
  data-description="{{ product['description']|lower }}"
472
  data-category="{{ product.get('category', 'Без категории') }}">
@@ -477,18 +507,18 @@ def catalog():
477
  loading="lazy">
478
  </div>
479
  {% endif %}
 
 
 
480
  <h2>{{ product['name'] }}</h2>
481
  <div class="product-price">
 
482
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
483
- <span>Розница: {{ product['price'] }} с</span><br>
484
- <span>Опт (от {{ product['min_wholesale'] }}): {{ product['wholesale_price'] }} с</span>
485
- {% else %}
486
- {{ product['price'] }} с
487
  {% endif %}
488
  </div>
489
  <p class="product-description">{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}</p>
490
- <button class="product-button" onclick="openModal({{ loop.index0 }})">Подробнее</button>
491
- <button class="product-button add-to-cart" onclick="openQuantityModal({{ loop.index0 }})">В корзину</button>
492
  </div>
493
  {% endfor %}
494
  </div>
@@ -570,9 +600,7 @@ def catalog():
570
  document.getElementById('productModal').style.display = "block";
571
  }
572
 
573
- function
574
-
575
- closeModal(modalId) {
576
  document.getElementById(modalId).style.display = "none";
577
  }
578
 
@@ -758,7 +786,7 @@ def categories_page():
758
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
759
  <title>Категории</title>
760
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
761
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
762
  <style>
763
  * {
764
  margin: 0;
@@ -766,19 +794,19 @@ def categories_page():
766
  box-sizing: border-box;
767
  }
768
  body {
769
- font-family: 'Poppins', sans-serif;
770
- background: linear-gradient(135deg, #f0f2f5, #e9ecef);
771
- color: #2d3748;
772
  line-height: 1.6;
773
  transition: background 0.3s, color 0.3s;
774
  padding-bottom: 60px;
775
  }
776
  body.dark-mode {
777
- background: linear-gradient(135deg, #1a202c, #2d3748);
778
- color: #e2e8f0;
779
  }
780
  .container {
781
- max-width: 1300px;
782
  margin: 0 auto;
783
  padding: 20px;
784
  }
@@ -787,62 +815,67 @@ def categories_page():
787
  justify-content: space-between;
788
  align-items: center;
789
  padding: 15px 0;
790
- border-bottom: 1px solid #e2e8f0;
791
- }
792
- .header-logo {
793
- width: 60px;
794
- height: 60px;
795
- border-radius: 50%;
796
- object-fit: cover;
797
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
798
- transition: transform 0.3s ease, box-shadow 0.3s ease;
799
- }
800
- .header-logo:hover {
801
- transform: scale(1.1);
802
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
803
  }
804
  .header h1 {
805
- font-size: 1.5rem;
806
- font-weight: 600;
807
- margin-left: 15px;
 
 
 
808
  }
809
  .theme-toggle {
810
  background: none;
811
  border: none;
812
  font-size: 1.5rem;
813
  cursor: pointer;
814
- color: #4a5568;
815
  transition: color 0.3s ease;
816
  }
817
  .theme-toggle:hover {
818
  color: #526df2;
819
  }
 
 
 
820
  .categories-grid {
821
  display: grid;
822
- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
823
- gap: 15px;
824
  padding: 10px;
825
  }
826
  .category-item {
827
- background: #fff;
 
828
  border-radius: 15px;
829
- padding: 15px;
830
  text-align: center;
831
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
832
- transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
833
  text-decoration: none;
834
- color: #2d3748;
835
  }
836
  body.dark-mode .category-item {
837
- background: #2d3748;
838
- color: #e2e8f0;
 
839
  }
840
  .category-item:hover {
841
- transform: translateY(-5px) scale(1.02);
842
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
 
843
  background-color: #526df2;
844
  color: white;
845
  }
 
 
 
 
 
 
 
 
846
  .navbar {
847
  position: fixed;
848
  bottom: 0;
@@ -856,11 +889,11 @@ def categories_page():
856
  z-index: 1000;
857
  }
858
  body.dark-mode .navbar {
859
- background-color: #2d3748;
860
  }
861
  .navbar a {
862
  text-align: center;
863
- color: #4a5568;
864
  text-decoration: none;
865
  font-size: 0.9rem;
866
  transition: color 0.3s ease;
@@ -874,7 +907,7 @@ def categories_page():
874
  margin-bottom: 5px;
875
  }
876
  body.dark-mode .navbar a {
877
- color: #a0aec0;
878
  }
879
  .navbar a:hover {
880
  color: #526df2;
@@ -884,7 +917,6 @@ def categories_page():
884
  <body>
885
  <div class="container">
886
  <div class="header">
887
- <img src="''' + LOGO_URL + '''" alt="Logo" class="header-logo">
888
  <h1>Категории</h1>
889
  <button class="theme-toggle" onclick="toggleTheme()">
890
  <i class="fas fa-moon"></i>
@@ -947,7 +979,7 @@ def category_products(category):
947
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
948
  <title>{{ category }}</title>
949
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
950
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
951
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
952
  <style>
953
  * {
@@ -956,19 +988,19 @@ def category_products(category):
956
  box-sizing: border-box;
957
  }
958
  body {
959
- font-family: 'Poppins', sans-serif;
960
- background: linear-gradient(135deg, #f0f2f5, #e9ecef);
961
- color: #2d3748;
962
  line-height: 1.6;
963
  transition: background 0.3s, color 0.3s;
964
  padding-bottom: 60px;
965
  }
966
  body.dark-mode {
967
- background: linear-gradient(135deg, #1a202c, #2d3748);
968
- color: #e2e8f0;
969
  }
970
  .container {
971
- max-width: 1300px;
972
  margin: 0 auto;
973
  padding: 20px;
974
  }
@@ -977,57 +1009,60 @@ def category_products(category):
977
  justify-content: space-between;
978
  align-items: center;
979
  padding: 15px 0;
980
- border-bottom: 1px solid #e2e8f0;
981
- }
982
- .header-logo {
983
- width: 60px;
984
- height: 60px;
985
- border-radius: 50%;
986
- object-fit: cover;
987
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
988
- transition: transform 0.3s ease, box-shadow 0.3s ease;
989
- }
990
- .header-logo:hover {
991
- transform: scale(1.1);
992
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
993
  }
994
  .header h1 {
995
- font-size: 1.5rem;
996
- font-weight: 600;
997
- margin-left: 15px;
 
 
 
998
  }
999
  .theme-toggle {
1000
  background: none;
1001
  border: none;
1002
  font-size: 1.5rem;
1003
  cursor: pointer;
1004
- color: #4a5568;
1005
  transition: color 0.3s ease;
1006
  }
1007
  .theme-toggle:hover {
1008
  color: #526df2;
1009
  }
 
 
 
1010
  .products-grid {
1011
  display: grid;
1012
- grid-template-columns: repeat(2, minmax(200px, 1fr));
1013
- gap: 15px;
1014
  padding: 10px;
1015
  }
1016
  .product {
1017
- background: #fff;
 
1018
  border-radius: 15px;
1019
  padding: 15px;
1020
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
1021
- transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease;
 
 
1022
  overflow: hidden;
1023
  }
 
 
 
 
 
1024
  body.dark-mode .product {
1025
- background: #2d3748;
1026
- color: #fff;
 
1027
  }
1028
- .product:hover {
1029
- transform: translateY(-5px) scale(1.02);
1030
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
1031
  }
1032
  .product-image {
1033
  width: 100%;
@@ -1038,6 +1073,10 @@ def category_products(category):
1038
  display: flex;
1039
  justify-content: center;
1040
  align-items: center;
 
 
 
 
1041
  }
1042
  .product-image img {
1043
  max-width: 100%;
@@ -1046,11 +1085,11 @@ def category_products(category):
1046
  transition: transform 0.3s ease;
1047
  }
1048
  .product-image img:hover {
1049
- transform: scale(1.1);
1050
  }
1051
  .product h2 {
1052
- font-size: 1rem;
1053
- font-weight: 600;
1054
  margin: 10px 0;
1055
  text-align: center;
1056
  white-space: nowrap;
@@ -1058,15 +1097,22 @@ def category_products(category):
1058
  text-overflow: ellipsis;
1059
  }
1060
  .product-price {
1061
- font-size: 1.1rem;
1062
- color: #ef4444;
1063
  font-weight: 700;
1064
  text-align: center;
1065
  margin: 5px 0;
1066
  }
 
 
 
 
 
 
 
1067
  .product-description {
1068
- font-size: 0.8rem;
1069
- color: #718096;
1070
  text-align: center;
1071
  margin-bottom: 15px;
1072
  overflow: hidden;
@@ -1074,17 +1120,17 @@ def category_products(category):
1074
  white-space: nowrap;
1075
  }
1076
  body.dark-mode .product-description {
1077
- color: #a0aec0;
1078
  }
1079
  .product-button {
1080
  display: block;
1081
  width: 100%;
1082
- padding: 8px;
1083
  border: none;
1084
- border-radius: 8px;
1085
  background-color: #526df2;
1086
  color: white;
1087
- font-size: 0.8rem;
1088
  font-weight: 500;
1089
  cursor: pointer;
1090
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
@@ -1098,29 +1144,32 @@ def category_products(category):
1098
  transform: translateY(-2px);
1099
  }
1100
  .add-to-cart {
1101
- background-color: #10b981;
1102
  }
1103
  .add-to-cart:hover {
1104
- background-color: #059669;
1105
- box-shadow: 0 4px 15px rgba(5, 150, 105, 0.4);
1106
  }
1107
  #cart-button {
1108
  position: fixed;
1109
  bottom: 80px;
1110
  right: 20px;
1111
- background-color: #ef4444;
1112
  color: white;
1113
  border: none;
1114
  border-radius: 50%;
1115
- width: 50px;
1116
- height: 50px;
1117
- font-size: 1.2rem;
1118
  cursor: pointer;
1119
  display: none;
1120
- box-shadow: 0 4px 15px rgba(239, 68, 68, 0.4);
1121
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1122
  z-index: 1000;
1123
  }
 
 
 
1124
  .modal {
1125
  display: none;
1126
  position: fixed;
@@ -1143,8 +1192,8 @@ def category_products(category):
1143
  animation: slideIn 0.3s ease-out;
1144
  }
1145
  body.dark-mode .modal-content {
1146
- background: #2d3748;
1147
- color: #e2e8f0;
1148
  }
1149
  @keyframes slideIn {
1150
  from { transform: translateY(-50px); opacity: 0; }
@@ -1153,15 +1202,15 @@ def category_products(category):
1153
  .close {
1154
  float: right;
1155
  font-size: 1.5rem;
1156
- color: #718096;
1157
  cursor: pointer;
1158
  transition: color 0.3s;
1159
  }
1160
  .close:hover {
1161
- color: #2d3748;
1162
  }
1163
  body.dark-mode .close {
1164
- color: #a0aec0;
1165
  }
1166
  body.dark-mode .close:hover {
1167
  color: #fff;
@@ -1171,10 +1220,10 @@ def category_products(category):
1171
  justify-content: space-between;
1172
  align-items: center;
1173
  padding: 15px 0;
1174
- border-bottom: 1px solid #e2e8f0;
1175
  }
1176
  body.dark-mode .cart-item {
1177
- border-bottom: 1px solid #4a5568;
1178
  }
1179
  .cart-item img {
1180
  width: 50px;
@@ -1187,24 +1236,24 @@ def category_products(category):
1187
  width: 100%;
1188
  max-width: 150px;
1189
  padding: 8px;
1190
- border: 1px solid #e2e8f0;
1191
  border-radius: 8px;
1192
  font-size: 1rem;
1193
  margin: 5px 0;
1194
  }
1195
  .clear-cart {
1196
- background-color: #ef4444;
1197
  }
1198
  .clear-cart:hover {
1199
- background-color: #dc2626;
1200
- box-shadow: 0 4px 15px rgba(220, 38, 38, 0.4);
1201
  }
1202
  .order-button {
1203
- background-color: #10b981;
1204
  }
1205
  .order-button:hover {
1206
- background-color: #059669;
1207
- box-shadow: 0 4px 15px rgba(5, 150, 105, 0.4);
1208
  }
1209
  .navbar {
1210
  position: fixed;
@@ -1219,11 +1268,11 @@ def category_products(category):
1219
  z-index: 1000;
1220
  }
1221
  body.dark-mode .navbar {
1222
- background-color: #2d3748;
1223
  }
1224
  .navbar a {
1225
  text-align: center;
1226
- color: #4a5568;
1227
  text-decoration: none;
1228
  font-size: 0.9rem;
1229
  transition: color 0.3s ease;
@@ -1237,17 +1286,27 @@ def category_products(category):
1237
  margin-bottom: 5px;
1238
  }
1239
  body.dark-mode .navbar a {
1240
- color: #a0aec0;
1241
  }
1242
  .navbar a:hover {
1243
  color: #526df2;
1244
  }
 
 
 
 
 
 
 
 
 
 
 
1245
  </style>
1246
  </head>
1247
  <body>
1248
  <div class="container">
1249
  <div class="header">
1250
- <img src="''' + LOGO_URL + '''" alt="Logo" class="header-logo">
1251
  <h1>{{ category }}</h1>
1252
  <button class="theme-toggle" onclick="toggleTheme()">
1253
  <i class="fas fa-moon"></i>
@@ -1256,6 +1315,7 @@ def category_products(category):
1256
  <div class="products-grid" id="products-grid">
1257
  {% for product in products %}
1258
  <div class="product"
 
1259
  data-name="{{ product['name']|lower }}"
1260
  data-description="{{ product['description']|lower }}"
1261
  data-category="{{ product.get('category', 'Без категории') }}">
@@ -1266,18 +1326,18 @@ def category_products(category):
1266
  loading="lazy">
1267
  </div>
1268
  {% endif %}
 
 
 
1269
  <h2>{{ product['name'] }}</h2>
1270
  <div class="product-price">
 
1271
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
1272
- <span>Розница: {{ product['price'] }} с</span><br>
1273
- <span>Опт (от {{ product['min_wholesale'] }}): {{ product['wholesale_price'] }} с</span>
1274
- {% else %}
1275
- {{ product['price'] }} с
1276
  {% endif %}
1277
  </div>
1278
  <p class="product-description">{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}</p>
1279
- <button class="product-button" onclick="openModal({{ loop.index0 }})">Подробнее</button>
1280
- <button class="product-button add-to-cart" onclick="openQuantityModal({{ loop.index0 }})">В корзину</button>
1281
  </div>
1282
  {% endfor %}
1283
  </div>
@@ -1693,12 +1753,12 @@ def admin():
1693
  <meta charset="UTF-8">
1694
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1695
  <title>Админ-панель</title>
1696
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
1697
  <style>
1698
  body {
1699
- font-family: 'Poppins', sans-serif;
1700
- background: linear-gradient(135deg, #f0f2f5, #e9ecef);
1701
- color: #2d3748;
1702
  padding: 20px;
1703
  }
1704
  .container {
@@ -1709,20 +1769,15 @@ def admin():
1709
  display: flex;
1710
  align-items: center;
1711
  padding: 15px 0;
1712
- border-bottom: 1px solid #e2e8f0;
1713
- }
1714
- .header-logo {
1715
- width: 60px;
1716
- height: 60px;
1717
- border-radius: 50%;
1718
- object-fit: cover;
1719
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
1720
- transition: transform 0.3s ease, box-shadow 0.3s ease;
1721
- margin-right: 15px;
1722
  }
1723
- .header-logo:hover {
1724
- transform: scale(1.1);
1725
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
 
 
 
 
1726
  }
1727
  h1, h2 {
1728
  font-weight: 600;
@@ -1744,7 +1799,7 @@ def admin():
1744
  width: 100%;
1745
  padding: 12px;
1746
  margin-top: 5px;
1747
- border: 1px solid #e2e8f0;
1748
  border-radius: 8px;
1749
  font-size: 1rem;
1750
  transition: all 0.3s ease;
@@ -1771,11 +1826,11 @@ def admin():
1771
  transform: translateY(-2px);
1772
  }
1773
  .delete-button {
1774
- background-color: #ef4444;
1775
  }
1776
  .delete-button:hover {
1777
- background-color: #dc2626;
1778
- box-shadow: 0 4px 15px rgba(220, 38, 38, 0.4);
1779
  }
1780
  .product-list, .category-list {
1781
  display: grid;
@@ -1799,17 +1854,16 @@ def admin():
1799
  margin-top: 5px;
1800
  }
1801
  .add-color-btn {
1802
- background-color: #10b981;
1803
  }
1804
  .add-color-btn:hover {
1805
- background-color: #059669;
1806
  }
1807
  </style>
1808
  </head>
1809
  <body>
1810
  <div class="container">
1811
  <div class="header">
1812
- <img src="''' + LOGO_URL + '''" alt="Logo" class="header-logo">
1813
  <h1>Админ-панель</h1>
1814
  </div>
1815
  <h1>Добавление товара</h1>
@@ -1849,51 +1903,39 @@ def admin():
1849
  <input type="hidden" name="action" value="add_category">
1850
  <label>Название категории:</label>
1851
  <input type="text" name="category_name" required>
1852
- <button type="submit">Добавить</button>
1853
  </form>
1854
 
1855
- <h2>Список категорий</h2>
1856
  <div class="category-list">
1857
  {% for category in categories %}
1858
  <div class="category-item">
1859
- <h3>{{ category }}</h3>
1860
- <form method="POST" style="display: inline;">
1861
  <input type="hidden" name="action" value="delete_category">
1862
  <input type="hidden" name="category_index" value="{{ loop.index0 }}">
1863
- <button type="submit" class="delete-button">Удалить</button>
1864
  </form>
1865
  </div>
1866
  {% endfor %}
1867
  </div>
1868
 
1869
- <h2>Управление базой данных</h2>
1870
- <form method="POST" action="{{ url_for('backup') }}" style="display: inline;">
1871
- <button type="submit">Создать копию</button>
1872
- </form>
1873
- <form method="GET" action="{{ url_for('download') }}" style="display: inline;">
1874
- <button type="submit">Скачать базу</button>
1875
- </form>
1876
-
1877
- <h2>Список товаров</h2>
1878
  <div class="product-list">
1879
  {% for product in products %}
1880
  <div class="product-item">
1881
- <h3>{{ product['name'] }}</h3>
1882
- <p><strong>Категория:</strong> {{ product.get('category', 'Без категории') }}</p>
1883
- <p><strong>Цена (розница):</strong> {{ product['price'] }} с</p>
1884
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
1885
- <p><strong>Цена (опт, от {{ product['min_wholesale'] }}):</strong> {{ product['wholesale_price'] }} с</p>
1886
  {% endif %}
1887
- <p><strong>Описание:</strong> {{ product['description'] }}</p>
1888
- <p><strong>Цвета:</strong> {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
1889
- {% if product.get('photos') and product['photos']|length > 0 %}
1890
- <div style="display: flex; flex-wrap: wrap; gap: 10px;">
1891
- {% for photo in product['photos'] %}
1892
- <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}"
1893
- alt="{{ product['name'] }}"
1894
- style="max-width: 100px; border-radius: 10px;">
1895
- {% endfor %}
1896
- </div>
1897
  {% endif %}
1898
  <details>
1899
  <summary>Редактировать</summary>
@@ -1971,6 +2013,4 @@ if __name__ == '__main__':
1971
  load_data()
1972
  except Exception as e:
1973
  logging.error(f"Не удалось загрузить базу данных: {e}")
1974
- app.run(debug=True, host='0.0.0.0', port=7860)
1975
-
1976
-
 
17
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
18
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ")
19
 
 
 
 
20
  # Настройка логирования
21
  logging.basicConfig(level=logging.DEBUG)
22
 
 
102
  <head>
103
  <meta charset="UTF-8">
104
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
105
+ <title>Канцелярия Оптом</title>
106
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
107
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
108
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
109
  <style>
110
  * {
 
113
  box-sizing: border-box;
114
  }
115
  body {
116
+ font-family: 'Roboto', sans-serif;
117
+ background: linear-gradient(135deg, #f5f7fa, #e4e7eb);
118
+ color: #333;
119
  line-height: 1.6;
120
  transition: background 0.3s, color 0.3s;
121
+ padding-bottom: 60px;
122
  }
123
  body.dark-mode {
124
+ background: linear-gradient(135deg, #1a1a2e, #2a2a3e);
125
+ color: #e0e0e0;
126
  }
127
  .container {
128
+ max-width: 1400px;
129
  margin: 0 auto;
130
  padding: 20px;
131
  }
 
134
  justify-content: space-between;
135
  align-items: center;
136
  padding: 15px 0;
137
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
139
  .header h1 {
140
+ font-size: 2rem;
141
+ font-weight: 700;
142
+ letter-spacing: 1px;
143
+ background: linear-gradient(90deg, #526df2, #7a8ff5);
144
+ -webkit-background-clip: text;
145
+ -webkit-text-fill-color: transparent;
146
  }
147
  .theme-toggle {
148
  background: none;
149
  border: none;
150
  font-size: 1.5rem;
151
  cursor: pointer;
152
+ color: #666;
153
  transition: color 0.3s ease;
154
  }
155
  .theme-toggle:hover {
156
  color: #526df2;
157
  }
158
+ body.dark-mode .theme-toggle {
159
+ color: #bbb;
160
+ }
161
  .filters-container {
162
  margin: 20px 0;
163
  display: flex;
 
174
  max-width: 600px;
175
  padding: 12px 18px;
176
  font-size: 1rem;
177
+ border: 1px solid rgba(0, 0, 0, 0.1);
178
+ border-radius: 25px;
179
  outline: none;
180
  box-shadow: 0 2px 5px rgba(0,0,0,0.05);
181
  transition: all 0.3s ease;
 
185
  box-shadow: 0 4px 15px rgba(82, 109, 242, 0.2);
186
  }
187
  .category-filter {
188
+ padding: 10px 20px;
189
+ border: 1px solid rgba(0, 0, 0, 0.1);
190
+ border-radius: 25px;
191
  background-color: #fff;
192
  cursor: pointer;
193
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
194
  font-size: 0.9rem;
195
+ font-weight: 500;
196
  }
197
  .category-filter.active, .category-filter:hover {
198
  background-color: #526df2;
 
200
  border-color: #526df2;
201
  box-shadow: 0 2px 10px rgba(82, 109, 242, 0.3);
202
  }
203
+ body.dark-mode .category-filter {
204
+ background-color: #2a2a3e;
205
+ border-color: rgba(255, 255, 255, 0.1);
206
+ color: #e0e0e0;
207
+ }
208
  .products-grid {
209
  display: grid;
210
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
211
+ gap: 20px;
212
  padding: 10px;
213
  }
214
  .product {
215
+ background: rgba(255, 255, 255, 0.8);
216
+ border: 1px solid rgba(0, 0, 0, 0.05);
217
  border-radius: 15px;
218
  padding: 15px;
219
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
220
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease, background 0.3s ease;
221
+ cursor: pointer;
222
+ position: relative;
223
  overflow: hidden;
224
  }
225
+ .product:hover {
226
+ transform: translateY(-5px);
227
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
228
+ background: rgba(255, 255, 255, 0.9);
229
+ }
230
  body.dark-mode .product {
231
+ background: rgba(42, 42, 62, 0.8);
232
+ border-color: rgba(255, 255, 255, 0.05);
233
+ color: #e0e0e0;
234
  }
235
+ body.dark-mode .product:hover {
236
+ background: rgba(42, 42, 62, 0.9);
237
+ box-shadow: 0 8px 25px rgba(255, 255, 255, 0.1);
238
  }
239
  .product-image {
240
  width: 100%;
 
245
  display: flex;
246
  justify-content: center;
247
  align-items: center;
248
+ transition: transform 0.3s ease;
249
+ }
250
+ body.dark-mode .product-image {
251
+ background-color: #333;
252
  }
253
  .product-image img {
254
  max-width: 100%;
 
257
  transition: transform 0.3s ease;
258
  }
259
  .product-image img:hover {
260
+ transform: scale(1.05);
261
  }
262
  .product h2 {
263
+ font-size: 1.1rem;
264
+ font-weight: 500;
265
  margin: 10px 0;
266
  text-align: center;
267
  white-space: nowrap;
 
269
  text-overflow: ellipsis;
270
  }
271
  .product-price {
272
+ font-size: 1.2rem;
273
+ color: #e63946;
274
  font-weight: 700;
275
  text-align: center;
276
  margin: 5px 0;
277
  }
278
+ .product-price .wholesale {
279
+ font-size: 0.9rem;
280
+ color: #526df2;
281
+ font-weight: 500;
282
+ display: block;
283
+ margin-top: 5px;
284
+ }
285
  .product-description {
286
+ font-size: 0.85rem;
287
+ color: #666;
288
  text-align: center;
289
  margin-bottom: 15px;
290
  overflow: hidden;
 
292
  white-space: nowrap;
293
  }
294
  body.dark-mode .product-description {
295
+ color: #bbb;
296
  }
297
  .product-button {
298
  display: block;
299
  width: 100%;
300
+ padding: 10px;
301
  border: none;
302
+ border-radius: 25px;
303
  background-color: #526df2;
304
  color: white;
305
+ font-size: 0.9rem;
306
  font-weight: 500;
307
  cursor: pointer;
308
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 
316
  transform: translateY(-2px);
317
  }
318
  .add-to-cart {
319
+ background-color: #2ecc71;
320
  }
321
  .add-to-cart:hover {
322
+ background-color: #27ae60;
323
+ box-shadow: 0 4px 15px rgba(46, 204, 113, 0.4);
324
  }
325
  #cart-button {
326
  position: fixed;
327
  bottom: 80px;
328
  right: 20px;
329
+ background-color: #e63946;
330
  color: white;
331
  border: none;
332
  border-radius: 50%;
333
+ width: 60px;
334
+ height: 60px;
335
+ font-size: 1.5rem;
336
  cursor: pointer;
337
  display: none;
338
+ box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
339
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
340
  z-index: 1000;
341
  }
342
+ #cart-button:hover {
343
+ transform: scale(1.1);
344
+ }
345
  .modal {
346
  display: none;
347
  position: fixed;
 
364
  animation: slideIn 0.3s ease-out;
365
  }
366
  body.dark-mode .modal-content {
367
+ background: #2a2a3e;
368
+ color: #e0e0e0;
369
  }
370
  @keyframes slideIn {
371
  from { transform: translateY(-50px); opacity: 0; }
 
374
  .close {
375
  float: right;
376
  font-size: 1.5rem;
377
+ color: #666;
378
  cursor: pointer;
379
  transition: color 0.3s;
380
  }
381
  .close:hover {
382
+ color: #333;
383
  }
384
  body.dark-mode .close {
385
+ color: #bbb;
386
  }
387
  body.dark-mode .close:hover {
388
  color: #fff;
 
392
  justify-content: space-between;
393
  align-items: center;
394
  padding: 15px 0;
395
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
396
  }
397
  body.dark-mode .cart-item {
398
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
399
  }
400
  .cart-item img {
401
  width: 50px;
 
408
  width: 100%;
409
  max-width: 150px;
410
  padding: 8px;
411
+ border: 1px solid rgba(0, 0, 0, 0.1);
412
  border-radius: 8px;
413
  font-size: 1rem;
414
  margin: 5px 0;
415
  }
416
  .clear-cart {
417
+ background-color: #e63946;
418
  }
419
  .clear-cart:hover {
420
+ background-color: #d62828;
421
+ box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
422
  }
423
  .order-button {
424
+ background-color: #2ecc71;
425
  }
426
  .order-button:hover {
427
+ background-color: #27ae60;
428
+ box-shadow: 0 4px 15px rgba(46, 204, 113, 0.4);
429
  }
430
  .navbar {
431
  position: fixed;
 
440
  z-index: 1000;
441
  }
442
  body.dark-mode .navbar {
443
+ background-color: #2a2a3e;
444
  }
445
  .navbar a {
446
  text-align: center;
447
+ color: #666;
448
  text-decoration: none;
449
  font-size: 0.9rem;
450
  transition: color 0.3s ease;
 
458
  margin-bottom: 5px;
459
  }
460
  body.dark-mode .navbar a {
461
+ color: #bbb;
462
  }
463
  .navbar a:hover {
464
  color: #526df2;
465
  }
466
+ .wholesale-badge {
467
+ position: absolute;
468
+ top: 10px;
469
+ right: 10px;
470
+ background-color: #526df2;
471
+ color: white;
472
+ padding: 5px 10px;
473
+ border-radius: 15px;
474
+ font-size: 0.75rem;
475
+ font-weight: 500;
476
+ }
477
  </style>
478
  </head>
479
  <body>
480
  <div class="container">
481
  <div class="header">
482
+ <h1>Канцелярия Оптом</h1>
 
483
  <button class="theme-toggle" onclick="toggleTheme()">
484
  <i class="fas fa-moon"></i>
485
  </button>
 
496
  <div class="products-grid" id="products-grid">
497
  {% for product in products %}
498
  <div class="product"
499
+ onclick="openModal({{ loop.index0 }})"
500
  data-name="{{ product['name']|lower }}"
501
  data-description="{{ product['description']|lower }}"
502
  data-category="{{ product.get('category', 'Без категории') }}">
 
507
  loading="lazy">
508
  </div>
509
  {% endif %}
510
+ {% if product.get('wholesale_price') and product.get('min_wholesale') %}
511
+ <span class="wholesale-badge">Опт от {{ product['min_wholesale'] }}</span>
512
+ {% endif %}
513
  <h2>{{ product['name'] }}</h2>
514
  <div class="product-price">
515
+ <span>{{ product['price'] }} с</span>
516
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
517
+ <span class="wholesale">Опт: {{ product['wholesale_price'] }} с</span>
 
 
 
518
  {% endif %}
519
  </div>
520
  <p class="product-description">{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}</p>
521
+ <button class="product-button add-to-cart" onclick="event.stopPropagation(); openQuantityModal({{ loop.index0 }})">В корзину</button>
 
522
  </div>
523
  {% endfor %}
524
  </div>
 
600
  document.getElementById('productModal').style.display = "block";
601
  }
602
 
603
+ function closeModal(modalId) {
 
 
604
  document.getElementById(modalId).style.display = "none";
605
  }
606
 
 
786
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
787
  <title>Категории</title>
788
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
789
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
790
  <style>
791
  * {
792
  margin: 0;
 
794
  box-sizing: border-box;
795
  }
796
  body {
797
+ font-family: 'Roboto', sans-serif;
798
+ background: linear-gradient(135deg, #f5f7fa, #e4e7eb);
799
+ color: #333;
800
  line-height: 1.6;
801
  transition: background 0.3s, color 0.3s;
802
  padding-bottom: 60px;
803
  }
804
  body.dark-mode {
805
+ background: linear-gradient(135deg, #1a1a2e, #2a2a3e);
806
+ color: #e0e0e0;
807
  }
808
  .container {
809
+ max-width: 1400px;
810
  margin: 0 auto;
811
  padding: 20px;
812
  }
 
815
  justify-content: space-between;
816
  align-items: center;
817
  padding: 15px 0;
818
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
819
  }
820
  .header h1 {
821
+ font-size: 2rem;
822
+ font-weight: 700;
823
+ letter-spacing: 1px;
824
+ background: linear-gradient(90deg, #526df2, #7a8ff5);
825
+ -webkit-background-clip: text;
826
+ -webkit-text-fill-color: transparent;
827
  }
828
  .theme-toggle {
829
  background: none;
830
  border: none;
831
  font-size: 1.5rem;
832
  cursor: pointer;
833
+ color: #666;
834
  transition: color 0.3s ease;
835
  }
836
  .theme-toggle:hover {
837
  color: #526df2;
838
  }
839
+ body.dark-mode .theme-toggle {
840
+ color: #bbb;
841
+ }
842
  .categories-grid {
843
  display: grid;
844
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
845
+ gap: 20px;
846
  padding: 10px;
847
  }
848
  .category-item {
849
+ background: rgba(255, 255, 255, 0.8);
850
+ border: 1px solid rgba(0, 0, 0, 0.05);
851
  border-radius: 15px;
852
+ padding: 20px;
853
  text-align: center;
854
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
855
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease, background 0.3s ease;
856
  text-decoration: none;
857
+ color: #333;
858
  }
859
  body.dark-mode .category-item {
860
+ background: rgba(42, 42, 62, 0.8);
861
+ border-color: rgba(255, 255, 255, 0.05);
862
+ color: #e0e0e0;
863
  }
864
  .category-item:hover {
865
+ transform: translateY(-5px);
866
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
867
+ background: rgba(255, 255, 255, 0.9);
868
  background-color: #526df2;
869
  color: white;
870
  }
871
+ body.dark-mode .category-item:hover {
872
+ background: rgba(42, 42, 62, 0.9);
873
+ box-shadow: 0 8px 25px rgba(255, 255, 255, 0.1);
874
+ }
875
+ .category-item h2 {
876
+ font-size: 1.2rem;
877
+ font-weight: 500;
878
+ }
879
  .navbar {
880
  position: fixed;
881
  bottom: 0;
 
889
  z-index: 1000;
890
  }
891
  body.dark-mode .navbar {
892
+ background-color: #2a2a3e;
893
  }
894
  .navbar a {
895
  text-align: center;
896
+ color: #666;
897
  text-decoration: none;
898
  font-size: 0.9rem;
899
  transition: color 0.3s ease;
 
907
  margin-bottom: 5px;
908
  }
909
  body.dark-mode .navbar a {
910
+ color: #bbb;
911
  }
912
  .navbar a:hover {
913
  color: #526df2;
 
917
  <body>
918
  <div class="container">
919
  <div class="header">
 
920
  <h1>Категории</h1>
921
  <button class="theme-toggle" onclick="toggleTheme()">
922
  <i class="fas fa-moon"></i>
 
979
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
980
  <title>{{ category }}</title>
981
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
982
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
983
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/10.2.0/swiper-bundle.min.css">
984
  <style>
985
  * {
 
988
  box-sizing: border-box;
989
  }
990
  body {
991
+ font-family: 'Roboto', sans-serif;
992
+ background: linear-gradient(135deg, #f5f7fa, #e4e7eb);
993
+ color: #333;
994
  line-height: 1.6;
995
  transition: background 0.3s, color 0.3s;
996
  padding-bottom: 60px;
997
  }
998
  body.dark-mode {
999
+ background: linear-gradient(135deg, #1a1a2e, #2a2a3e);
1000
+ color: #e0e0e0;
1001
  }
1002
  .container {
1003
+ max-width: 1400px;
1004
  margin: 0 auto;
1005
  padding: 20px;
1006
  }
 
1009
  justify-content: space-between;
1010
  align-items: center;
1011
  padding: 15px 0;
1012
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
1013
  }
1014
  .header h1 {
1015
+ font-size: 2rem;
1016
+ font-weight: 700;
1017
+ letter-spacing: 1px;
1018
+ background: linear-gradient(90deg, #526df2, #7a8ff5);
1019
+ -webkit-background-clip: text;
1020
+ -webkit-text-fill-color: transparent;
1021
  }
1022
  .theme-toggle {
1023
  background: none;
1024
  border: none;
1025
  font-size: 1.5rem;
1026
  cursor: pointer;
1027
+ color: #666;
1028
  transition: color 0.3s ease;
1029
  }
1030
  .theme-toggle:hover {
1031
  color: #526df2;
1032
  }
1033
+ body.dark-mode .theme-toggle {
1034
+ color: #bbb;
1035
+ }
1036
  .products-grid {
1037
  display: grid;
1038
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
1039
+ gap: 20px;
1040
  padding: 10px;
1041
  }
1042
  .product {
1043
+ background: rgba(255, 255, 255, 0.8);
1044
+ border: 1px solid rgba(0, 0, 0, 0.05);
1045
  border-radius: 15px;
1046
  padding: 15px;
1047
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
1048
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease, background 0.3s ease;
1049
+ cursor: pointer;
1050
+ position: relative;
1051
  overflow: hidden;
1052
  }
1053
+ .product:hover {
1054
+ transform: translateY(-5px);
1055
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
1056
+ background: rgba(255, 255, 255, 0.9);
1057
+ }
1058
  body.dark-mode .product {
1059
+ background: rgba(42, 42, 62, 0.8);
1060
+ border-color: rgba(255, 255, 255, 0.05);
1061
+ color: #e0e0e0;
1062
  }
1063
+ body.dark-mode .product:hover {
1064
+ background: rgba(42, 42, 62, 0.9);
1065
+ box-shadow: 0 8px 25px rgba(255, 255, 255, 0.1);
1066
  }
1067
  .product-image {
1068
  width: 100%;
 
1073
  display: flex;
1074
  justify-content: center;
1075
  align-items: center;
1076
+ transition: transform 0.3s ease;
1077
+ }
1078
+ body.dark-mode .product-image {
1079
+ background-color: #333;
1080
  }
1081
  .product-image img {
1082
  max-width: 100%;
 
1085
  transition: transform 0.3s ease;
1086
  }
1087
  .product-image img:hover {
1088
+ transform: scale(1.05);
1089
  }
1090
  .product h2 {
1091
+ font-size: 1.1rem;
1092
+ font-weight: 500;
1093
  margin: 10px 0;
1094
  text-align: center;
1095
  white-space: nowrap;
 
1097
  text-overflow: ellipsis;
1098
  }
1099
  .product-price {
1100
+ font-size: 1.2rem;
1101
+ color: #e63946;
1102
  font-weight: 700;
1103
  text-align: center;
1104
  margin: 5px 0;
1105
  }
1106
+ .product-price .wholesale {
1107
+ font-size: 0.9rem;
1108
+ color: #526df2;
1109
+ font-weight: 500;
1110
+ display: block;
1111
+ margin-top: 5px;
1112
+ }
1113
  .product-description {
1114
+ font-size: 0.85rem;
1115
+ color: #666;
1116
  text-align: center;
1117
  margin-bottom: 15px;
1118
  overflow: hidden;
 
1120
  white-space: nowrap;
1121
  }
1122
  body.dark-mode .product-description {
1123
+ color: #bbb;
1124
  }
1125
  .product-button {
1126
  display: block;
1127
  width: 100%;
1128
+ padding: 10px;
1129
  border: none;
1130
+ border-radius: 25px;
1131
  background-color: #526df2;
1132
  color: white;
1133
+ font-size: 0.9rem;
1134
  font-weight: 500;
1135
  cursor: pointer;
1136
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 
1144
  transform: translateY(-2px);
1145
  }
1146
  .add-to-cart {
1147
+ background-color: #2ecc71;
1148
  }
1149
  .add-to-cart:hover {
1150
+ background-color: #27ae60;
1151
+ box-shadow: 0 4px 15px rgba(46, 204, 113, 0.4);
1152
  }
1153
  #cart-button {
1154
  position: fixed;
1155
  bottom: 80px;
1156
  right: 20px;
1157
+ background-color: #e63946;
1158
  color: white;
1159
  border: none;
1160
  border-radius: 50%;
1161
+ width: 60px;
1162
+ height: 60px;
1163
+ font-size: 1.5rem;
1164
  cursor: pointer;
1165
  display: none;
1166
+ box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
1167
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
1168
  z-index: 1000;
1169
  }
1170
+ #cart-button:hover {
1171
+ transform: scale(1.1);
1172
+ }
1173
  .modal {
1174
  display: none;
1175
  position: fixed;
 
1192
  animation: slideIn 0.3s ease-out;
1193
  }
1194
  body.dark-mode .modal-content {
1195
+ background: #2a2a3e;
1196
+ color: #e0e0e0;
1197
  }
1198
  @keyframes slideIn {
1199
  from { transform: translateY(-50px); opacity: 0; }
 
1202
  .close {
1203
  float: right;
1204
  font-size: 1.5rem;
1205
+ color: #666;
1206
  cursor: pointer;
1207
  transition: color 0.3s;
1208
  }
1209
  .close:hover {
1210
+ color: #333;
1211
  }
1212
  body.dark-mode .close {
1213
+ color: #bbb;
1214
  }
1215
  body.dark-mode .close:hover {
1216
  color: #fff;
 
1220
  justify-content: space-between;
1221
  align-items: center;
1222
  padding: 15px 0;
1223
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
1224
  }
1225
  body.dark-mode .cart-item {
1226
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
1227
  }
1228
  .cart-item img {
1229
  width: 50px;
 
1236
  width: 100%;
1237
  max-width: 150px;
1238
  padding: 8px;
1239
+ border: 1px solid rgba(0, 0, 0, 0.1);
1240
  border-radius: 8px;
1241
  font-size: 1rem;
1242
  margin: 5px 0;
1243
  }
1244
  .clear-cart {
1245
+ background-color: #e63946;
1246
  }
1247
  .clear-cart:hover {
1248
+ background-color: #d62828;
1249
+ box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
1250
  }
1251
  .order-button {
1252
+ background-color: #2ecc71;
1253
  }
1254
  .order-button:hover {
1255
+ background-color: #27ae60;
1256
+ box-shadow: 0 4px 15px rgba(46, 204, 113, 0.4);
1257
  }
1258
  .navbar {
1259
  position: fixed;
 
1268
  z-index: 1000;
1269
  }
1270
  body.dark-mode .navbar {
1271
+ background-color: #2a2a3e;
1272
  }
1273
  .navbar a {
1274
  text-align: center;
1275
+ color: #666;
1276
  text-decoration: none;
1277
  font-size: 0.9rem;
1278
  transition: color 0.3s ease;
 
1286
  margin-bottom: 5px;
1287
  }
1288
  body.dark-mode .navbar a {
1289
+ color: #bbb;
1290
  }
1291
  .navbar a:hover {
1292
  color: #526df2;
1293
  }
1294
+ .wholesale-badge {
1295
+ position: absolute;
1296
+ top: 10px;
1297
+ right: 10px;
1298
+ background-color: #526df2;
1299
+ color: white;
1300
+ padding: 5px 10px;
1301
+ border-radius: 15px;
1302
+ font-size: 0.75rem;
1303
+ font-weight: 500;
1304
+ }
1305
  </style>
1306
  </head>
1307
  <body>
1308
  <div class="container">
1309
  <div class="header">
 
1310
  <h1>{{ category }}</h1>
1311
  <button class="theme-toggle" onclick="toggleTheme()">
1312
  <i class="fas fa-moon"></i>
 
1315
  <div class="products-grid" id="products-grid">
1316
  {% for product in products %}
1317
  <div class="product"
1318
+ onclick="openModal({{ loop.index0 }})"
1319
  data-name="{{ product['name']|lower }}"
1320
  data-description="{{ product['description']|lower }}"
1321
  data-category="{{ product.get('category', 'Без категории') }}">
 
1326
  loading="lazy">
1327
  </div>
1328
  {% endif %}
1329
+ {% if product.get('wholesale_price') and product.get('min_wholesale') %}
1330
+ <span class="wholesale-badge">Опт от {{ product['min_wholesale'] }}</span>
1331
+ {% endif %}
1332
  <h2>{{ product['name'] }}</h2>
1333
  <div class="product-price">
1334
+ <span>{{ product['price'] }} с</span>
1335
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
1336
+ <span class="wholesale">Опт: {{ product['wholesale_price'] }} с</span>
 
 
 
1337
  {% endif %}
1338
  </div>
1339
  <p class="product-description">{{ product['description'][:50] }}{% if product['description']|length > 50 %}...{% endif %}</p>
1340
+ <button class="product-button add-to-cart" onclick="event.stopPropagation(); openQuantityModal({{ loop.index0 }})">В корзину</button>
 
1341
  </div>
1342
  {% endfor %}
1343
  </div>
 
1753
  <meta charset="UTF-8">
1754
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1755
  <title>Админ-панель</title>
1756
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
1757
  <style>
1758
  body {
1759
+ font-family: 'Roboto', sans-serif;
1760
+ background: linear-gradient(135deg, #f5f7fa, #e4e7eb);
1761
+ color: #333;
1762
  padding: 20px;
1763
  }
1764
  .container {
 
1769
  display: flex;
1770
  align-items: center;
1771
  padding: 15px 0;
1772
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
1773
  }
1774
+ .header h1 {
1775
+ font-size: 2rem;
1776
+ font-weight: 700;
1777
+ letter-spacing: 1px;
1778
+ background: linear-gradient(90deg, #526df2, #7a8ff5);
1779
+ -webkit-background-clip: text;
1780
+ -webkit-text-fill-color: transparent;
1781
  }
1782
  h1, h2 {
1783
  font-weight: 600;
 
1799
  width: 100%;
1800
  padding: 12px;
1801
  margin-top: 5px;
1802
+ border: 1px solid rgba(0, 0, 0, 0.1);
1803
  border-radius: 8px;
1804
  font-size: 1rem;
1805
  transition: all 0.3s ease;
 
1826
  transform: translateY(-2px);
1827
  }
1828
  .delete-button {
1829
+ background-color: #e63946;
1830
  }
1831
  .delete-button:hover {
1832
+ background-color: #d62828;
1833
+ box-shadow: 0 4px 15px rgba(230, 57, 70, 0.4);
1834
  }
1835
  .product-list, .category-list {
1836
  display: grid;
 
1854
  margin-top: 5px;
1855
  }
1856
  .add-color-btn {
1857
+ background-color: #2ecc71;
1858
  }
1859
  .add-color-btn:hover {
1860
+ background-color: #27ae60;
1861
  }
1862
  </style>
1863
  </head>
1864
  <body>
1865
  <div class="container">
1866
  <div class="header">
 
1867
  <h1>Админ-панель</h1>
1868
  </div>
1869
  <h1>Добавление товара</h1>
 
1903
  <input type="hidden" name="action" value="add_category">
1904
  <label>Название категории:</label>
1905
  <input type="text" name="category_name" required>
1906
+ <button type="submit">Добавить категорию</button>
1907
  </form>
1908
 
 
1909
  <div class="category-list">
1910
  {% for category in categories %}
1911
  <div class="category-item">
1912
+ <h2>{{ category }}</h2>
1913
+ <form method="POST">
1914
  <input type="hidden" name="action" value="delete_category">
1915
  <input type="hidden" name="category_index" value="{{ loop.index0 }}">
1916
+ <button type="submit" class="delete-button">Удалить категорию</button>
1917
  </form>
1918
  </div>
1919
  {% endfor %}
1920
  </div>
1921
 
1922
+ <h1>��писок товаров</h1>
 
 
 
 
 
 
 
 
1923
  <div class="product-list">
1924
  {% for product in products %}
1925
  <div class="product-item">
1926
+ <h2>{{ product['name'] }}</h2>
1927
+ <p>Цена (розница): {{ product['price'] }} с</p>
 
1928
  {% if product.get('wholesale_price') and product.get('min_wholesale') %}
1929
+ <p>Цена (опт): {{ product['wholesale_price'] }} с (от {{ product['min_wholesale'] }})</p>
1930
  {% endif %}
1931
+ <p>Описание: {{ product['description'] }}</p>
1932
+ <p>Категория: {{ product.get('category', 'Без категории') }}</p>
1933
+ <p>Цвета: {{ product.get('colors', ['Нет цветов'])|join(', ') }}</p>
1934
+ {% if product.get('photos') %}
1935
+ <p>Фотографии:</p>
1936
+ {% for photo in product['photos'] %}
1937
+ <img src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/photos/{{ photo }}" alt="{{ product['name'] }}" style="max-width: 100px; margin: 5px;">
1938
+ {% endfor %}
 
 
1939
  {% endif %}
1940
  <details>
1941
  <summary>Редактировать</summary>
 
2013
  load_data()
2014
  except Exception as e:
2015
  logging.error(f"Не удалось загрузить базу данных: {e}")
2016
+ app.run(debug=True, host='0.0.0.0', port=7860)