Update main.py
Browse files
main.py
CHANGED
@@ -135,45 +135,6 @@ def proxy(path):
|
|
135 |
img['src'] = proxy_url
|
136 |
img['style'] = 'max-width: 100%; height: auto; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 10px 0;'
|
137 |
|
138 |
-
# Add responsive styles
|
139 |
-
style_tag = soup.new_tag('style')
|
140 |
-
style_tag.string = '''
|
141 |
-
/* Base styles */
|
142 |
-
body { margin: 0; padding: 15px; font-family: Arial, sans-serif; }
|
143 |
-
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
|
144 |
-
td, th { padding: 8px; border: 1px solid #ddd; }
|
145 |
-
img { max-width: 100%; height: auto; }
|
146 |
-
.open-image-btn { display: inline-block; margin: 10px; padding: 8px 15px; background-color: #4a90e2; border: none; border-radius: 4px; text-decoration: none; color: white; font-weight: 500; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
147 |
-
|
148 |
-
/* Responsive styles */
|
149 |
-
@media (max-width: 768px) {
|
150 |
-
body { padding: 10px; }
|
151 |
-
table { font-size: 14px; }
|
152 |
-
td, th { padding: 6px; }
|
153 |
-
.open-image-btn { display: block; margin: 10px 0; text-align: center; }
|
154 |
-
}
|
155 |
-
|
156 |
-
@media (max-width: 480px) {
|
157 |
-
table { font-size: 12px; }
|
158 |
-
td, th { padding: 4px; }
|
159 |
-
img { margin: 5px 0; }
|
160 |
-
.zoom-controls { display: flex; justify-content: space-between; width: 100%; margin-bottom: 10px; }
|
161 |
-
.zoom-btn { flex: 1; margin: 0 2px; }
|
162 |
-
}
|
163 |
-
'''
|
164 |
-
|
165 |
-
if soup.head:
|
166 |
-
soup.head.append(style_tag)
|
167 |
-
else:
|
168 |
-
head_tag = soup.new_tag('head')
|
169 |
-
head_tag.append(style_tag)
|
170 |
-
if soup.html:
|
171 |
-
soup.html.insert(0, head_tag)
|
172 |
-
else:
|
173 |
-
html_tag = soup.new_tag('html')
|
174 |
-
html_tag.append(head_tag)
|
175 |
-
soup.append(html_tag)
|
176 |
-
|
177 |
# Add "Open Original Image" button next to each image
|
178 |
button = soup.new_tag('a')
|
179 |
button['href'] = proxy_url
|
@@ -265,18 +226,33 @@ def proxy(path):
|
|
265 |
|
266 |
// Touch gestures for mobile
|
267 |
let initialDistance = 0;
|
|
|
|
|
|
|
|
|
268 |
modal.addEventListener('touchstart', function(e) {
|
269 |
if (e.touches.length === 2) {
|
|
|
270 |
initialDistance = Math.hypot(
|
271 |
e.touches[0].pageX - e.touches[1].pageX,
|
272 |
e.touches[0].pageY - e.touches[1].pageY
|
273 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
}
|
275 |
});
|
276 |
|
277 |
modal.addEventListener('touchmove', function(e) {
|
|
|
|
|
278 |
if (e.touches.length === 2) {
|
279 |
-
|
280 |
const currentDistance = Math.hypot(
|
281 |
e.touches[0].pageX - e.touches[1].pageX,
|
282 |
e.touches[0].pageY - e.touches[1].pageY
|
@@ -285,7 +261,35 @@ def proxy(path):
|
|
285 |
scale = Math.min(Math.max(scale + delta, 0.5), 3);
|
286 |
initialDistance = currentDistance;
|
287 |
applyTransform();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
}
|
|
|
289 |
});
|
290 |
|
291 |
// Add click event to all images
|
@@ -449,10 +453,20 @@ def proxy(path):
|
|
449 |
backdrop-filter: blur(10px);
|
450 |
border: 1px solid rgba(255, 255, 255, 0.8);
|
451 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
td {
|
453 |
padding: 20px;
|
454 |
border: 1px solid rgba(236, 240, 241, 0.8);
|
455 |
transition: var(--transition);
|
|
|
456 |
}
|
457 |
tr:nth-child(even) {
|
458 |
background: rgba(245, 247, 250, 0.5);
|
@@ -578,22 +592,42 @@ def proxy(path):
|
|
578 |
color: #3498db;
|
579 |
}
|
580 |
|
|
|
581 |
@media (max-width: 768px) {
|
582 |
-
body {
|
|
|
|
|
|
|
583 |
.breadcrumb {
|
584 |
flex-direction: column;
|
585 |
align-items: flex-start;
|
586 |
padding: 15px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
587 |
}
|
588 |
ul {
|
589 |
grid-template-columns: 1fr;
|
590 |
gap: 15px;
|
591 |
}
|
592 |
-
table {
|
593 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
.open-image-btn {
|
595 |
width: 100%;
|
596 |
text-align: center;
|
|
|
597 |
}
|
598 |
.modal img {
|
599 |
max-width: 95%;
|
@@ -603,6 +637,69 @@ def proxy(path):
|
|
603 |
top: 10px;
|
604 |
right: 15px;
|
605 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
}
|
607 |
'''
|
608 |
# Check if head exists, if not create it
|
@@ -614,8 +711,21 @@ def proxy(path):
|
|
614 |
html_tag = soup.new_tag('html')
|
615 |
html_tag.append(head_tag)
|
616 |
soup.append(html_tag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
617 |
soup.head.append(style_tag)
|
618 |
|
|
|
|
|
|
|
|
|
|
|
|
|
619 |
# Convert navigation links to breadcrumb
|
620 |
nav_links = soup.find_all('a', href=True)
|
621 |
breadcrumb_div = soup.new_tag('div')
|
|
|
135 |
img['src'] = proxy_url
|
136 |
img['style'] = 'max-width: 100%; height: auto; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 10px 0;'
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
# Add "Open Original Image" button next to each image
|
139 |
button = soup.new_tag('a')
|
140 |
button['href'] = proxy_url
|
|
|
226 |
|
227 |
// Touch gestures for mobile
|
228 |
let initialDistance = 0;
|
229 |
+
let initialTouchX, initialTouchY;
|
230 |
+
let lastTouchX, lastTouchY;
|
231 |
+
let isTouchDragging = false;
|
232 |
+
|
233 |
modal.addEventListener('touchstart', function(e) {
|
234 |
if (e.touches.length === 2) {
|
235 |
+
// Pinch to zoom gesture
|
236 |
initialDistance = Math.hypot(
|
237 |
e.touches[0].pageX - e.touches[1].pageX,
|
238 |
e.touches[0].pageY - e.touches[1].pageY
|
239 |
);
|
240 |
+
} else if (e.touches.length === 1) {
|
241 |
+
// Single touch for dragging
|
242 |
+
isTouchDragging = true;
|
243 |
+
initialTouchX = e.touches[0].clientX - translateX;
|
244 |
+
initialTouchY = e.touches[0].clientY - translateY;
|
245 |
+
lastTouchX = e.touches[0].clientX;
|
246 |
+
lastTouchY = e.touches[0].clientY;
|
247 |
+
modalImg.style.transition = 'none';
|
248 |
}
|
249 |
});
|
250 |
|
251 |
modal.addEventListener('touchmove', function(e) {
|
252 |
+
e.preventDefault(); // Prevent page scrolling
|
253 |
+
|
254 |
if (e.touches.length === 2) {
|
255 |
+
// Pinch to zoom gesture
|
256 |
const currentDistance = Math.hypot(
|
257 |
e.touches[0].pageX - e.touches[1].pageX,
|
258 |
e.touches[0].pageY - e.touches[1].pageY
|
|
|
261 |
scale = Math.min(Math.max(scale + delta, 0.5), 3);
|
262 |
initialDistance = currentDistance;
|
263 |
applyTransform();
|
264 |
+
} else if (e.touches.length === 1 && isTouchDragging) {
|
265 |
+
// Single touch dragging
|
266 |
+
translateX = e.touches[0].clientX - initialTouchX;
|
267 |
+
translateY = e.touches[0].clientY - initialTouchY;
|
268 |
+
|
269 |
+
// Calculate velocity for momentum
|
270 |
+
lastTouchX = e.touches[0].clientX;
|
271 |
+
lastTouchY = e.touches[0].clientY;
|
272 |
+
|
273 |
+
applyTransform();
|
274 |
+
}
|
275 |
+
});
|
276 |
+
|
277 |
+
modal.addEventListener('touchend', function(e) {
|
278 |
+
isTouchDragging = false;
|
279 |
+
modalImg.style.transition = 'transform 0.3s ease-out';
|
280 |
+
});
|
281 |
+
|
282 |
+
// Double tap to reset zoom
|
283 |
+
let lastTap = 0;
|
284 |
+
modal.addEventListener('touchend', function(e) {
|
285 |
+
const currentTime = new Date().getTime();
|
286 |
+
const tapLength = currentTime - lastTap;
|
287 |
+
if (tapLength < 300 && tapLength > 0) {
|
288 |
+
// Double tap detected
|
289 |
+
resetZoom();
|
290 |
+
e.preventDefault();
|
291 |
}
|
292 |
+
lastTap = currentTime;
|
293 |
});
|
294 |
|
295 |
// Add click event to all images
|
|
|
453 |
backdrop-filter: blur(10px);
|
454 |
border: 1px solid rgba(255, 255, 255, 0.8);
|
455 |
}
|
456 |
+
/* Table container for horizontal scrolling on mobile */
|
457 |
+
.table-container {
|
458 |
+
width: 100%;
|
459 |
+
overflow-x: auto;
|
460 |
+
-webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
|
461 |
+
margin: 30px 0;
|
462 |
+
border-radius: 16px;
|
463 |
+
box-shadow: var(--card-shadow);
|
464 |
+
}
|
465 |
td {
|
466 |
padding: 20px;
|
467 |
border: 1px solid rgba(236, 240, 241, 0.8);
|
468 |
transition: var(--transition);
|
469 |
+
word-break: break-word; /* Break long words */
|
470 |
}
|
471 |
tr:nth-child(even) {
|
472 |
background: rgba(245, 247, 250, 0.5);
|
|
|
592 |
color: #3498db;
|
593 |
}
|
594 |
|
595 |
+
/* Responsive styles for tablets */
|
596 |
@media (max-width: 768px) {
|
597 |
+
body {
|
598 |
+
padding: 15px;
|
599 |
+
font-size: 15px;
|
600 |
+
}
|
601 |
.breadcrumb {
|
602 |
flex-direction: column;
|
603 |
align-items: flex-start;
|
604 |
padding: 15px;
|
605 |
+
margin-bottom: 20px;
|
606 |
+
}
|
607 |
+
.breadcrumb a {
|
608 |
+
padding: 6px 12px;
|
609 |
+
font-size: 14px;
|
610 |
+
width: 100%;
|
611 |
+
box-sizing: border-box;
|
612 |
+
margin-bottom: 5px;
|
613 |
}
|
614 |
ul {
|
615 |
grid-template-columns: 1fr;
|
616 |
gap: 15px;
|
617 |
}
|
618 |
+
table {
|
619 |
+
font-size: 14px;
|
620 |
+
display: block;
|
621 |
+
overflow-x: auto;
|
622 |
+
white-space: nowrap;
|
623 |
+
}
|
624 |
+
td {
|
625 |
+
padding: 12px;
|
626 |
+
}
|
627 |
.open-image-btn {
|
628 |
width: 100%;
|
629 |
text-align: center;
|
630 |
+
padding: 10px 15px;
|
631 |
}
|
632 |
.modal img {
|
633 |
max-width: 95%;
|
|
|
637 |
top: 10px;
|
638 |
right: 15px;
|
639 |
}
|
640 |
+
.close-container {
|
641 |
+
top: 10px;
|
642 |
+
right: 10px;
|
643 |
+
}
|
644 |
+
.zoom-controls {
|
645 |
+
display: flex;
|
646 |
+
gap: 5px;
|
647 |
+
}
|
648 |
+
}
|
649 |
+
|
650 |
+
/* Responsive styles for mobile phones */
|
651 |
+
@media (max-width: 480px) {
|
652 |
+
body {
|
653 |
+
padding: 10px;
|
654 |
+
font-size: 14px;
|
655 |
+
}
|
656 |
+
.breadcrumb {
|
657 |
+
padding: 10px;
|
658 |
+
margin-bottom: 15px;
|
659 |
+
}
|
660 |
+
.breadcrumb a {
|
661 |
+
padding: 5px 10px;
|
662 |
+
font-size: 13px;
|
663 |
+
}
|
664 |
+
table {
|
665 |
+
font-size: 12px;
|
666 |
+
}
|
667 |
+
td {
|
668 |
+
padding: 8px;
|
669 |
+
}
|
670 |
+
img {
|
671 |
+
margin: 5px 0;
|
672 |
+
}
|
673 |
+
.open-image-btn {
|
674 |
+
padding: 8px 12px;
|
675 |
+
font-size: 13px;
|
676 |
+
margin: 8px 0;
|
677 |
+
}
|
678 |
+
.modal {
|
679 |
+
padding: 0;
|
680 |
+
}
|
681 |
+
.modal img {
|
682 |
+
max-width: 100%;
|
683 |
+
max-height: 90vh;
|
684 |
+
}
|
685 |
+
.close-container {
|
686 |
+
top: 5px;
|
687 |
+
right: 5px;
|
688 |
+
gap: 5px;
|
689 |
+
}
|
690 |
+
.zoom-controls {
|
691 |
+
display: flex;
|
692 |
+
justify-content: space-between;
|
693 |
+
width: 100%;
|
694 |
+
margin-bottom: 5px;
|
695 |
+
}
|
696 |
+
.zoom-btn {
|
697 |
+
flex: 1;
|
698 |
+
margin: 0 2px;
|
699 |
+
padding: 4px 8px;
|
700 |
+
font-size: 12px;
|
701 |
+
}
|
702 |
+
}
|
703 |
}
|
704 |
'''
|
705 |
# Check if head exists, if not create it
|
|
|
711 |
html_tag = soup.new_tag('html')
|
712 |
html_tag.append(head_tag)
|
713 |
soup.append(html_tag)
|
714 |
+
|
715 |
+
# Add viewport meta tag for proper mobile scaling
|
716 |
+
viewport_meta = soup.new_tag('meta')
|
717 |
+
viewport_meta['name'] = 'viewport'
|
718 |
+
viewport_meta['content'] = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'
|
719 |
+
soup.head.append(viewport_meta)
|
720 |
+
|
721 |
soup.head.append(style_tag)
|
722 |
|
723 |
+
# Wrap tables in container for mobile scrolling
|
724 |
+
for table in soup.find_all('table'):
|
725 |
+
table_container = soup.new_tag('div')
|
726 |
+
table_container['class'] = 'table-container'
|
727 |
+
table.wrap(table_container)
|
728 |
+
|
729 |
# Convert navigation links to breadcrumb
|
730 |
nav_links = soup.find_all('a', href=True)
|
731 |
breadcrumb_div = soup.new_tag('div')
|