diff --git a/assets/preview.png b/assets/preview.png
new file mode 100644
index 0000000..9e059b8
Binary files /dev/null and b/assets/preview.png differ
diff --git a/index.html b/index.html
index 45297f0..1292154 100644
--- a/index.html
+++ b/index.html
@@ -8,20 +8,38 @@
+
+
You can only upload up to 10 images.
Instagram Formatter
-
diff --git a/script.js b/script.js
index c868cf8..a062296 100644
--- a/script.js
+++ b/script.js
@@ -1,42 +1,159 @@
-document.getElementById('uploadForm').addEventListener('submit', async function (event) {
- event.preventDefault();
+document.addEventListener('DOMContentLoaded', function () {
+ const uploadForm = document.getElementById('uploadForm');
+ const imageInput = document.getElementById('imageInput');
+ const doneImgsDiv = document.getElementById('done-imgs');
+ const progressContainer = document.getElementById('progress-container');
+ const errorMessage = document.getElementById('error-message');
- const formData = new FormData();
- const imageInput = document.getElementById('imageInput').files[0];
+ // Advanced Tab Toggle Functionality
+ document.querySelector(".collapsible").addEventListener("click", function () {
+ this.classList.toggle("active");
+ let content = this.nextElementSibling;
+ if (content.style.display === "block") {
+ content.style.display = "none";
+ } else {
+ content.style.display = "block";
+ }
+ });
- if (!imageInput) {
- alert("Please select an image to upload.");
- return;
- }
+ uploadForm.addEventListener('submit', function (event) {
+ document.getElementById('download-all').style.display = 'inline-block';
+ event.preventDefault();
- formData.append('image', imageInput);
+ const files = imageInput.files;
- try {
- const response = await fetch('https://api.nevets.tech/igformatter/upload', {
- method: 'POST',
- body: formData
- });
-
- if (!response.ok) {
- throw new Error('Image upload failed');
+ if (files.length === 0) {
+ alert("Please select at least one image to upload.");
+ return;
+ } else if (files.length > 10) {
+ errorMessage.style.display = 'block';
+ return;
+ } else {
+ errorMessage.style.display = 'none';
}
- const arrayBuffer = await response.arrayBuffer();
- downloadImage(arrayBuffer, imageInput.value);
+ // Clear previous progress bars and images if needed
+ progressContainer.innerHTML = '';
+ doneImgsDiv.innerHTML = '';
- } catch (error) {
- console.error('Error:', error);
- alert('There was an error processing your image.');
+ // Get user inputs
+ const color = document.getElementById("color")?.value || "#ffffff";
+ const width = document.getElementById("width")?.value || "1080";
+ const height = document.getElementById("height")?.value || "1080";
+ const minBorder = document.getElementById("min-border")?.value || "16";
+
+ Array.from(files).forEach((file) => {
+ uploadAndProcessImage(file, { color, width, height, minBorder });
+ });
+ });
+
+ function uploadAndProcessImage(file, options) {
+ const { color, width, height, minBorder } = options;
+
+ // Create progress bar elements
+ const progressWrapper = document.createElement('div');
+ progressWrapper.className = 'progress-wrapper';
+
+ const fileNameLabel = document.createElement('div');
+ fileNameLabel.className = 'file-name';
+ fileNameLabel.textContent = file.name;
+
+ const progressBar = document.createElement('div');
+ progressBar.className = 'progress-bar';
+
+ const progressBarFill = document.createElement('div');
+ progressBarFill.className = 'progress-bar-fill';
+
+ const progressStatus = document.createElement('div');
+ progressStatus.className = 'progress-status';
+ progressStatus.textContent = 'Starting upload...';
+
+ progressBar.appendChild(progressBarFill);
+ progressWrapper.appendChild(fileNameLabel);
+ progressWrapper.appendChild(progressBar);
+ progressWrapper.appendChild(progressStatus);
+ progressContainer.appendChild(progressWrapper);
+
+ const formData = new FormData();
+ formData.append('image', file);
+
+ const xhr = new XMLHttpRequest();
+
+ xhr.open('POST', `https://api.nevets.tech/igformatter/upload?color=${encodeURIComponent(color)}&width=${encodeURIComponent(width)}&height=${encodeURIComponent(height)}&minBorder=${encodeURIComponent(minBorder)}`, true);
+ xhr.responseType = 'blob';
+
+ // Upload progress event
+ xhr.upload.addEventListener('progress', function (e) {
+ if (e.lengthComputable) {
+ const percentComplete = ((e.loaded / e.total) * 50).toFixed(2); // 0% to 50%
+ progressBarFill.style.width = `${percentComplete}%`;
+ progressStatus.textContent = `Uploading... ${percentComplete}%`;
+ }
+ });
+
+ // Download progress event
+ xhr.addEventListener('progress', function (e) {
+ if (e.lengthComputable) {
+ const percentComplete = (50 + ((e.loaded / e.total) * 50)).toFixed(2); // 50% to 100%
+ progressBarFill.style.width = `${percentComplete}%`;
+ progressStatus.textContent = `Processing... ${percentComplete}%`;
+ } else {
+ progressStatus.textContent = `Processing...`;
+ }
+ });
+
+ // On successful completion
+ xhr.addEventListener('load', function () {
+ if (xhr.status === 200) {
+ progressBarFill.style.width = '100%';
+ progressStatus.textContent = 'Completed';
+ progressWrapper.classList.add('success');
+
+ const blob = xhr.response;
+ const imageUrl = URL.createObjectURL(blob);
+
+ const anchor = document.createElement('a');
+ anchor.href = imageUrl;
+ anchor.className = "card-link";
+ anchor.download = `${file.name.replace(/\.[^/.]+$/, "")}_formatted.png`;
+
+ const img = document.createElement('img');
+ img.src = imageUrl;
+ img.className = "card-img";
+ img.alt = "Formatted Image Preview";
+
+ anchor.appendChild(img);
+ doneImgsDiv.appendChild(anchor);
+ } else {
+ handleError(`Processing failed for ${file.name}`, progressWrapper, progressStatus, progressBarFill);
+ }
+ });
+
+ // On error
+ xhr.addEventListener('error', function () {
+ handleError(`An error occurred while uploading ${file.name}`, progressWrapper, progressStatus, progressBarFill);
+ });
+
+ // On abort
+ xhr.addEventListener('abort', function () {
+ handleError(`Upload aborted for ${file.name}`, progressWrapper, progressStatus, progressBarFill);
+ });
+
+ xhr.send(formData);
+ }
+
+ function handleError(message, progressWrapper, progressStatus, progressBarFill) {
+ console.error(message);
+ progressStatus.textContent = message;
+ progressWrapper.classList.add('error');
+ progressBarFill.style.width = '100%';
}
});
-function downloadImage(arrayBuffer, fileName) {
- const blob = new Blob([arrayBuffer], { type: "image/png" });
- const cardElement = document.getElementById("card");
-
- let urlCreator = window.URL || window.webkitURL;
- cardElement.href = urlCreator.createObjectURL(blob);
- cardElement.style.display = 'unset';
- cardElement.download = fileName + ".png";
- cardElement.click();
-}
+// Handle the download all functionality
+document.getElementById('download-all').addEventListener('click', function() {
+ const links = document.querySelectorAll('#done-imgs .card-link');
+ links.forEach(link => {
+ link.click();
+ });
+});
diff --git a/styles.css b/styles.css
index d6fa938..2d89506 100644
--- a/styles.css
+++ b/styles.css
@@ -3,7 +3,7 @@ body {
background-color: #f4f4f4;
display: flex;
justify-content: center;
- align-items: center;
+ align-items: flex-start;
height: 100vh;
margin: 0;
}
@@ -12,8 +12,10 @@ body {
background: white;
padding: 20px;
border-radius: 10px;
- box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
text-align: center;
+ max-width: 800px;
+ margin: auto;
}
h1 {
@@ -23,6 +25,9 @@ h1 {
input[type="file"] {
margin-bottom: 15px;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
}
button {
@@ -38,20 +43,160 @@ button:hover {
background-color: #0a85d9;
}
-#card {
- margin-top: 20px;
- display: inline-block;
- padding: 10px 20px;
- background-color: #28a745;
- color: white;
+/* Center the progress bars */
+#progress-container {
+ width: 100%;
+ max-width: 800px;
+ margin: 20px auto;
+ text-align: center;
+}
+
+.progress-wrapper {
+ margin-bottom: 10px;
+ padding: 10px;
+ background-color: #f9f9f9;
+ border: 1px solid #ddd;
border-radius: 5px;
- text-decoration: none;
+ width: 100%;
+ max-width: 400px;
+ margin-left: auto;
+ margin-right: auto;
}
-#card:hover {
- background-color: #218838;
+.progress-wrapper .file-name {
+ margin-bottom: 5px;
+ font-weight: bold;
+ color: #333;
}
-#preview {
+.progress-bar {
+ width: 100%;
+ background-color: #e6e6e6;
+ border-radius: 5px;
+ overflow: hidden;
+ height: 20px;
+ position: relative;
+}
+
+.progress-bar-fill {
+ height: 100%;
+ width: 0%;
+ background-color: #1da1f2;
+ transition: width 0.2s ease;
+}
+
+.progress-status {
+ margin-top: 5px;
+ font-size: 12px;
+ color: #555;
+}
+
+.progress-wrapper.success .progress-bar-fill {
+ background-color: #28a745;
+}
+
+.progress-wrapper.success .progress-status {
+ color: #28a745;
+}
+
+.progress-wrapper.error .progress-bar-fill {
+ background-color: #dc3545;
+}
+
+.progress-wrapper.error .progress-status {
+ color: #dc3545;
+}
+
+/* Responsive grid for images */
+#done-imgs {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
margin-top: 20px;
}
+
+.card-link {
+ flex: 1 1 calc(25% - 20px); /* 4 images per row with space */
+ margin: 10px;
+ max-width: calc(25% - 20px);
+ text-align: center;
+}
+
+.card-link img {
+ width: 100%;
+ height: auto;
+ border: 2px solid gray;
+ border-radius: 5px;
+}
+
+/* Advanced tab styling */
+.collapsible {
+ background-color: #1da1f2;
+ color: white;
+ padding: 10px 20px;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ width: 100%;
+ text-align: center;
+ outline: none;
+ font-size: 16px;
+ margin-top: 20px;
+}
+
+.collapsible:hover {
+ background-color: #0a85d9;
+}
+
+.collapsible:after {
+ content: '\002B'; /* Unicode character for "plus" sign (+) */
+ font-weight: bold;
+}
+
+.collapsible.active:after {
+ content: "\2212"; /* Unicode character for "minus" sign (−) */
+}
+
+.content {
+ padding: 10px 20px;
+ display: none;
+ overflow: hidden;
+ background-color: #f1f1f1;
+ margin-top: 10px;
+ border-radius: 5px;
+ text-align: left;
+}
+
+.content input[type="text"],
+.content input[type="number"],
+.content input[type="color"] {
+ margin: 5px 10px;
+ padding: 8px;
+ width: 80px;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.content label {
+ margin: 5px 10px;
+ display: inline-block;
+ text-align: left;
+ color: #333;
+ vertical-align: middle;
+}
+
+.content input[type="color"] {
+ width: 50px;
+ height: 30px;
+ padding: 0;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ cursor: pointer;
+ background-color: #fff;
+ -webkit-appearance: none;
+ appearance: none;
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
+}