diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..2ab8f05 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,55 @@ +events { + worker_connections 1024; + multi_accept on; + use epoll; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + keepalive_timeout 65; + + # Disable access logs for cleaner output + access_log off; + error_log /var/log/nginx/error.log warn; + + server { + listen 80; + server_name _; + + # Root is set to uploads directory + root /var/www/html/uploads; + index index.html index.htm; + + # Strip /uploads/ prefix if present (from Caddy routing) + location ~ ^/uploads/(.*)$ { + rewrite ^/uploads/(.*)$ /$1 break; + try_files $uri =404; + } + + # Direct access without /uploads/ prefix + location / { + try_files $uri $uri/ =404; + } + + # Enable directory listing for uploads + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + + # Security: deny access to database files + location ~ \.(sqlite3|db)$ { + deny all; + return 404; + } + + # Set proper MIME types for common file types + location ~* \.(jpg|jpeg|png|gif|ico|svg|pdf|zip|tar|gz|mov|mp4|avi)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + } + } +} + diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..2ab8f05 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,55 @@ +events { + worker_connections 1024; + multi_accept on; + use epoll; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + keepalive_timeout 65; + + # Disable access logs for cleaner output + access_log off; + error_log /var/log/nginx/error.log warn; + + server { + listen 80; + server_name _; + + # Root is set to uploads directory + root /var/www/html/uploads; + index index.html index.htm; + + # Strip /uploads/ prefix if present (from Caddy routing) + location ~ ^/uploads/(.*)$ { + rewrite ^/uploads/(.*)$ /$1 break; + try_files $uri =404; + } + + # Direct access without /uploads/ prefix + location / { + try_files $uri $uri/ =404; + } + + # Enable directory listing for uploads + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + + # Security: deny access to database files + location ~ \.(sqlite3|db)$ { + deny all; + return 404; + } + + # Set proper MIME types for common file types + location ~* \.(jpg|jpeg|png|gif|ico|svg|pdf|zip|tar|gz|mov|mp4|avi)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + } + } +} + diff --git a/static/css/quote_upload.css b/static/css/quote_upload.css index 2d0c5f9..289ed6d 100644 --- a/static/css/quote_upload.css +++ b/static/css/quote_upload.css @@ -21,6 +21,7 @@ body { min-height: 100vh; background: white; padding: 16px; + padding-bottom: 200px; /* Reserve space for progress bar and files */ display: flex; flex-direction: column; } diff --git a/static/js/quote_upload.js b/static/js/quote_upload.js index c7b11b3..6aa3bce 100644 --- a/static/js/quote_upload.js +++ b/static/js/quote_upload.js @@ -78,6 +78,11 @@ submitBtn.addEventListener('click', async () => { progressContainer.style.display = 'block'; progressFill.style.width = '0%'; progressMessage.textContent = 'Starting...'; + + // Scroll to progress bar so it's visible (for Google Pages iframe compatibility) + setTimeout(() => { + progressContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + }, 100); try { // Create FormData