0.5.0: A functional shit frontend made by chatgpt because I hate frontend so much
This commit is contained in:
parent
e096ed5215
commit
b2395b3dea
11 changed files with 518 additions and 99 deletions
|
@ -5,4 +5,6 @@ I'm making this to replace my current File uploader hosted on https://ayaya.beau
|
|||
|
||||
## TODO
|
||||
|
||||
- Add file size limit
|
||||
- ~~Add file size limit~~ ADDED
|
||||
- Fix error when accessing `http://127.0.0.1:8080` with an empty DB.
|
||||
- Better frontend...
|
|
@ -1,2 +0,0 @@
|
|||
blocked_extensions:
|
||||
- "exe"
|
BIN
public/chatterino.png
Normal file
BIN
public/chatterino.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
140
public/script.js
Normal file
140
public/script.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const dropArea = document.getElementById("drop-area");
|
||||
const fileInput = document.getElementById("fileElem");
|
||||
const uploadStatus = document.getElementById("upload-status");
|
||||
|
||||
// Prevent default drag behaviors
|
||||
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, preventDefaults, false);
|
||||
document.body.addEventListener(eventName, preventDefaults, false);
|
||||
});
|
||||
|
||||
// Highlight drop area when item is dragged over
|
||||
["dragenter", "dragover"].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, highlight, false);
|
||||
});
|
||||
|
||||
["dragleave", "drop"].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, unhighlight, false);
|
||||
});
|
||||
|
||||
// Handle dropped files
|
||||
dropArea.addEventListener("drop", handleDrop, false);
|
||||
dropArea.addEventListener("click", () => fileInput.click());
|
||||
|
||||
// Handle file selection
|
||||
fileInput.addEventListener("change", () => {
|
||||
const files = fileInput.files;
|
||||
handleFiles(files);
|
||||
}, false);
|
||||
|
||||
// Handle pasted files
|
||||
document.addEventListener("paste", handlePaste, false);
|
||||
|
||||
function preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function highlight() {
|
||||
dropArea.classList.add("highlight");
|
||||
}
|
||||
|
||||
function unhighlight() {
|
||||
dropArea.classList.remove("highlight");
|
||||
}
|
||||
|
||||
function handleDrop(e) {
|
||||
const dt = e.dataTransfer;
|
||||
const files = dt.files;
|
||||
handleFiles(files);
|
||||
}
|
||||
|
||||
function handlePaste(e) {
|
||||
const items = e.clipboardData.items;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (item.kind === "file") {
|
||||
const file = item.getAsFile();
|
||||
handleFiles([file]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleFiles(files) {
|
||||
if (files.length > 0) {
|
||||
for (const file of files) {
|
||||
uploadFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uploadFile(file) {
|
||||
const url = "upload"; // Replace with your upload URL
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
// Create a new upload status container and link elements
|
||||
const uploadContainer = document.createElement("div");
|
||||
const statusLink = document.createElement("div");
|
||||
const uploadText = document.createElement("span");
|
||||
const copyButton = document.createElement("button");
|
||||
|
||||
uploadContainer.className = "upload-status"; // Use the existing CSS class for styling
|
||||
uploadContainer.appendChild(uploadText);
|
||||
uploadContainer.appendChild(statusLink);
|
||||
uploadContainer.appendChild(copyButton);
|
||||
uploadStatus.appendChild(uploadContainer); // Append to the main upload status container
|
||||
|
||||
// Update upload text
|
||||
uploadText.innerHTML = "0%";
|
||||
uploadText.className = "percent"
|
||||
copyButton.className = "copy-button"; // Add class for styling
|
||||
copyButton.innerHTML = "Copy Link"; // Set button text
|
||||
copyButton.style.display = "none"; // Hide initially
|
||||
|
||||
// Update progress text
|
||||
xhr.upload.addEventListener("progress", (e) => {
|
||||
if (e.lengthComputable) {
|
||||
const percentComplete = Math.round((e.loaded / e.total) * 100);
|
||||
uploadText.innerHTML = `${percentComplete}%`; // Update the text with the percentage
|
||||
}
|
||||
});
|
||||
|
||||
// Handle response
|
||||
xhr.onload = () => {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
const fileLink = response.link; // Assuming the response contains a key 'link'
|
||||
statusLink.innerHTML = `<a href="${fileLink}" target="_blank">${fileLink}</a>`;
|
||||
copyButton.style.display = "inline"; // Show the copy button
|
||||
copyButton.onclick = () => copyToClipboard(fileLink); // Set the copy action
|
||||
} catch (error) {
|
||||
statusLink.textContent = "File uploaded but failed to parse response.";
|
||||
}
|
||||
} else {
|
||||
statusLink.textContent = "File upload failed.";
|
||||
}
|
||||
};
|
||||
|
||||
// Handle errors
|
||||
xhr.onerror = () => {
|
||||
statusLink.textContent = "An error occurred during the file upload.";
|
||||
};
|
||||
|
||||
// Send file
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
xhr.open("POST", url, true);
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
// Function to copy the link to the clipboard
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
// alert("Link copied to clipboard!"); // Notify the user
|
||||
}).catch(err => {
|
||||
console.error("Failed to copy: ", err);
|
||||
});
|
||||
}
|
||||
});
|
11
public/sharex.sxcu
Normal file
11
public/sharex.sxcu
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"Version": "14.0.1",
|
||||
"DestinationType": "ImageUploader, FileUploader",
|
||||
"RequestMethod": "POST",
|
||||
"RequestURL": "https://ayaya.beauty/upload",
|
||||
"Body": "MultipartFormData",
|
||||
"FileFormName": "file",
|
||||
"URL": "{json:link}",
|
||||
"DeletionURL": "{json:deleteLink}",
|
||||
"ErrorMessage": "{json:error}"
|
||||
}
|
135
public/styles.css
Normal file
135
public/styles.css
Normal file
|
@ -0,0 +1,135 @@
|
|||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #111;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
p, h1, h2, h3, h4, h5 {
|
||||
color: aliceblue
|
||||
}
|
||||
|
||||
.percent {
|
||||
color: aliceblue
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: auto;
|
||||
/* background: white; */
|
||||
padding: 20px;
|
||||
border-radius: 0px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#drop-area {
|
||||
/*! border: 2px solid #00ff00; */
|
||||
/*! border-radius: 6px; */
|
||||
/*! padding-left: 10px; */
|
||||
/*! padding-right: 10px; */
|
||||
text-align: center;
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
margin: 0 auto; /* Center the element */
|
||||
display: block; /* Ensure it behaves as a block-level element */
|
||||
background: rgba(202,230,190,.75);
|
||||
border: 1px solid #b7d1a0;
|
||||
border-radius: 4px;
|
||||
color: #468847;
|
||||
cursor: pointer;
|
||||
/*! display: inline-block; */
|
||||
font-size: 24px;
|
||||
padding: 28px 48px;
|
||||
text-shadow: 0 1px hsla(0,0%,100%,.5);
|
||||
transition: background-color .25s,width .5s,height .5s;
|
||||
}
|
||||
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
/* background: #; */
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
/* margin-top: 10px; */
|
||||
}
|
||||
|
||||
.upload-status {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
margin-top: 5px;
|
||||
padding: 5px 10px;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
display: none; /* Hidden initially */
|
||||
}
|
||||
|
||||
nav a, nav > ul
|
||||
{
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#upload-status {
|
||||
margin: 20px; /* Adjust as needed */
|
||||
}
|
||||
|
||||
.upload-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border: 2px solid #f40101; /* Optional styling for the status box */
|
||||
padding: 10px; /* Optional padding */
|
||||
border-radius: 6px; /* Optional rounded corners */
|
||||
/*! background-color: #f9f9f9; */ /* Optional background color */
|
||||
}
|
||||
|
||||
.link-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto; /* Pushes the link and button to the right */
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #ffb6c1;
|
||||
text-decoration: none; /* Remove underline from link */
|
||||
margin-right: 5px; /* Space between link and button */
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
text-decoration: underline; /* Optional: underline on hover */
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
display: inline;
|
||||
background-color: #5e5e5e; /* Button background color */
|
||||
color: white; /* Button text color */
|
||||
border: none; /* Remove border */
|
||||
border-radius: 3px; /* Rounded corners for the button */
|
||||
padding: 5px 10px; /* Button padding */
|
||||
cursor: pointer; /* Pointer cursor on hover */
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: #404040; /* Darker shade on hover */
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #ffb6c1
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #ffb6c1
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #ffb6c1
|
||||
}
|
165
public/upload.js
Normal file
165
public/upload.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
// document.addEventListener("DOMContentLoaded", () => {
|
||||
// const dropArea = document.getElementById("drop-area");
|
||||
// const fileInput = document.getElementById("fileElem");
|
||||
// const progressContainer = document.getElementById("progress-container");
|
||||
// const progressBar = document.getElementById("progress-bar");
|
||||
// const status = document.getElementById("status");
|
||||
|
||||
// // Prevent default drag behaviors
|
||||
// ["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
|
||||
// dropArea.addEventListener(eventName, preventDefaults, false);
|
||||
// document.body.addEventListener(eventName, preventDefaults, false);
|
||||
// });
|
||||
|
||||
// // Highlight drop area when item is dragged over
|
||||
// ["dragenter", "dragover"].forEach(eventName => {
|
||||
// dropArea.addEventListener(eventName, highlight, false);
|
||||
// });
|
||||
|
||||
// ["dragleave", "drop"].forEach(eventName => {
|
||||
// dropArea.addEventListener(eventName, unhighlight, false);
|
||||
// });
|
||||
|
||||
// // Handle dropped files
|
||||
// dropArea.addEventListener("drop", handleDrop, false);
|
||||
// dropArea.addEventListener("click", () => fileInput.click());
|
||||
|
||||
// // Handle file selection
|
||||
// fileInput.addEventListener("change", () => {
|
||||
// const files = fileInput.files;
|
||||
// handleFiles(files);
|
||||
// }, false);
|
||||
|
||||
// // Handle pasted files
|
||||
// document.addEventListener("paste", handlePaste, false);
|
||||
|
||||
// function preventDefaults(e) {
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// }
|
||||
|
||||
// function highlight() {
|
||||
// dropArea.classList.add("highlight");
|
||||
// }
|
||||
|
||||
// function unhighlight() {
|
||||
// dropArea.classList.remove("highlight");
|
||||
// }
|
||||
|
||||
// function handleDrop(e) {
|
||||
// const dt = e.dataTransfer;
|
||||
// const files = dt.files;
|
||||
// handleFiles(files);
|
||||
// }
|
||||
|
||||
// function handlePaste(e) {
|
||||
// const items = e.clipboardData.items;
|
||||
// for (let i = 0; i < items.length; i++) {
|
||||
// const item = items[i];
|
||||
// if (item.kind === "file") {
|
||||
// const file = item.getAsFile();
|
||||
// handleFiles([file]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// function handleFiles(files) {
|
||||
// if (files.length > 0) {
|
||||
// uploadFile(files[0]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// function uploadFile(file) {
|
||||
// const url = "upload"; // Replace with your upload URL
|
||||
// const xhr = new XMLHttpRequest();
|
||||
|
||||
// // Update progress bar
|
||||
// xhr.upload.addEventListener("progress", (e) => {
|
||||
// if (e.lengthComputable) {
|
||||
// const percentComplete = (e.loaded / e.total) * 100;
|
||||
// progressBar.style.width = percentComplete + "%"; // Set the width of the progress bar
|
||||
// progressContainer.style.display = "block"; // Show progress container
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Handle response
|
||||
// xhr.onload = () => {
|
||||
// if (xhr.status === 200) {
|
||||
// try {
|
||||
// const response = JSON.parse(xhr.responseText);
|
||||
// const fileLink = response.link; // Assuming the response contains a key 'link'
|
||||
// status.innerHTML = `<a href="${fileLink}" target="_blank">File uploaded successfully! Click here to view the file</a>`;
|
||||
// } catch (error) {
|
||||
// status.textContent = "File uploaded but failed to parse response.";
|
||||
// }
|
||||
// } else {
|
||||
// status.textContent = "File upload failed.";
|
||||
// }
|
||||
// progressBar.style.width = "0"; // Reset progress bar
|
||||
// progressContainer.style.display = "none"; // Hide progress container
|
||||
// };
|
||||
|
||||
// // Handle errors
|
||||
// xhr.onerror = () => {
|
||||
// status.textContent = "An error occurred during the file upload.";
|
||||
// progressBar.style.width = "0"; // Reset progress bar
|
||||
// progressContainer.style.display = "none"; // Hide progress container
|
||||
// };
|
||||
|
||||
// // Send file
|
||||
// const formData = new FormData();
|
||||
// formData.append("file", file);
|
||||
// xhr.open("POST", url, true);
|
||||
// xhr.send(formData);
|
||||
// }
|
||||
// });
|
||||
|
||||
function handleFiles(input) {
|
||||
const files = input.files;
|
||||
Array.from(files).forEach(file => {
|
||||
// Display download link initially
|
||||
document.querySelector(`#link-${file.name}`).textContent = "Uploading...";
|
||||
|
||||
// Create a new FormData instance
|
||||
let formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
// Simulate a request to the server
|
||||
fetch('/upload', { method: 'POST', body: formData })
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Update the progress bar
|
||||
document.querySelector(`#progress-${file.name}`).style.width = `${data.progress}%`;
|
||||
|
||||
// Display the download link
|
||||
document.querySelector(`#link-${file.name}`).textContent = data.link;
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
});
|
||||
}
|
||||
|
||||
// Handle drag & drop
|
||||
document.addEventListener('dragover', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
document.addEventListener('drop', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const files = event.dataTransfer.files;
|
||||
handleFiles(files);
|
||||
}, false);
|
||||
|
||||
// Handle clipboard paste
|
||||
document.addEventListener('paste', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const items = event.clipboardData.items;
|
||||
if (items.length > 0 && items[0].type.indexOf("text") !== -1) {
|
||||
const file = items[0].getAsFile();
|
||||
handleFiles([file]);
|
||||
}
|
||||
}, false);
|
|
@ -4,6 +4,7 @@ class Config
|
|||
include YAML::Serializable
|
||||
|
||||
property files : String = "./files"
|
||||
property secure : Bool = false
|
||||
property db : String = "./db.sqlite3"
|
||||
property filename_lenght : Int8 = 3
|
||||
# In MiB
|
||||
|
@ -16,6 +17,8 @@ class Config
|
|||
property delete_key_lenght : Int8 = 8
|
||||
# Blocked extensions that are not allowed to be uploaded to the server
|
||||
property blocked_extensions : Array(String) = [] of String
|
||||
property siteInfo : String = "xd"
|
||||
property siteWarning : String? = ""
|
||||
|
||||
def self.load
|
||||
config_file = "config/config.yml"
|
||||
|
|
|
@ -14,10 +14,16 @@ CONFIG = Config.load
|
|||
Kemal.config.port = CONFIG.port
|
||||
SQL = DB.open("sqlite3://#{CONFIG.db}")
|
||||
|
||||
# https://github.com/iv-org/invidious/blob/90e94d4e6cc126a8b7a091d12d7a5556bfe369d5/src/invidious.cr#L78
|
||||
CURRENT_BRANCH = {{ "#{`git branch | sed -n '/* /s///p'`.strip}" }}
|
||||
CURRENT_COMMIT = {{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit`.strip}" }}
|
||||
CURRENT_VERSION = {{ "#{`git log -1 --format=%ci | awk '{print $1}' | sed s/-/./g`.strip}" }}
|
||||
|
||||
Utils.create_db
|
||||
Utils.create_files_dir
|
||||
|
||||
get "/" do |env|
|
||||
host = env.request.headers["Host"]
|
||||
render "src/views/index.ecr"
|
||||
end
|
||||
|
||||
|
@ -47,3 +53,7 @@ end
|
|||
|
||||
CHECK_OLD_FILES.enqueue
|
||||
Kemal.run
|
||||
|
||||
{% if flag?(:release) || flag?(:production) %}
|
||||
Kemal.config.env = "production" if !ENV.has_key?("KEMAL_ENV")
|
||||
{% end %}
|
||||
|
|
|
@ -56,7 +56,8 @@ end
|
|||
if !filename.empty?
|
||||
JSON.build do |j|
|
||||
j.object do
|
||||
j.field "link", "https://#{env.request.headers["Host"]}/#{filename + extension}"
|
||||
CONFIG.secure ? j.field "link", "https://#{env.request.headers["Host"]}/#{filename}" : j.field "link", "http://#{env.request.headers["Host"]}/#{filename}"
|
||||
j.field "linkExt", "https://#{env.request.headers["Host"]}/#{filename}#{extension}"
|
||||
j.field "id", filename
|
||||
j.field "ext", extension
|
||||
j.field "name", original_filename
|
||||
|
@ -71,6 +72,7 @@ end
|
|||
end
|
||||
|
||||
def retrieve_file(env)
|
||||
puts env.params.url
|
||||
filename = SQL.query_one "SELECT filename FROM files WHERE filename = ?", env.params.url["filename"].to_s.split(".").first, as: String
|
||||
extension = SQL.query_one "SELECT extension FROM files WHERE filename = ?", filename, as: String
|
||||
send_file env, "#{CONFIG.files}/#{filename}#{extension}"
|
||||
|
@ -102,7 +104,7 @@ end
|
|||
file_extension = SQL.query_one "SELECT extension FROM files WHERE delete_key = ?", env.params.query["key"], as: String
|
||||
File.delete("#{CONFIG.files}/#{file_to_delete}#{file_extension}")
|
||||
SQL.exec "DELETE FROM files WHERE delete_key = ?", env.params.query["key"]
|
||||
msg("File deleted successfully")
|
||||
msg("File '#{file_to_delete}' deleted successfully")
|
||||
rescue ex
|
||||
error403("Unknown error: #{ex.message}")
|
||||
end
|
||||
|
|
|
@ -1,100 +1,53 @@
|
|||
<!-- <!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File Upload with Progress Bar</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>File Upload</h1>
|
||||
<div id="drop-area">
|
||||
<p>Drag & Drop your file here or click to upload</p>
|
||||
<input type="file" id="fileElem" accept="*/*" style="display: none;">
|
||||
<label for="fileElem" class="button">Select File</label>
|
||||
<div id="progress-container" style="display: none;">
|
||||
<div id="progress-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html> -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File Upload</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #111;
|
||||
color: aliceblue
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
margin: 60px 0;
|
||||
text-align: center;
|
||||
transition: width .5s, height .5s, margin .5s, padding .5s;
|
||||
}
|
||||
|
||||
#progressContainer {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
background-color: #343434;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#progressBar {
|
||||
height: 20px;
|
||||
width: 0;
|
||||
background-color: #6d95bb;
|
||||
}
|
||||
</style>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title> <%= host %> </title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="jumbotron">
|
||||
<div id="dropZone" class="drop-zone">
|
||||
<p>Drag and drop a file here or click to select</p>
|
||||
<input type="file" id="fileInput" name="file" style="display: none;">
|
||||
</div>
|
||||
<label for="fileInput"></label>
|
||||
<input type="file" id="fileInput">
|
||||
<button id="uploadButton">Upload File</button>
|
||||
<div id="progressContainer">
|
||||
<div id="progressBar"></div>
|
||||
</div>
|
||||
<div id="linkContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('uploadButton').addEventListener('click', () => {
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const file = fileInput.files[0];
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', 'upload', true);
|
||||
|
||||
// Track upload progress
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percentComplete = (event.loaded / event.total) * 100;
|
||||
document.getElementById('progressBar').style.width = percentComplete + '%';
|
||||
document.getElementById('progressBar').textContent = Math.round(percentComplete) + '%';
|
||||
}
|
||||
});
|
||||
|
||||
// Handle upload completion
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status === 200) {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
const linkContainer = document.getElementById('linkContainer');
|
||||
linkContainer.innerHTML = `<a href="${response.link}" target="_blank">View Uploaded File</a>`;
|
||||
} else if (xhr.status === 403) {
|
||||
const response = JSON.parse(xhr.responseText);
|
||||
const linkContainer = document.getElementById('linkContainer');
|
||||
linkContainer.innerHTML = `<a target="_blank">ERROR: ${response.error}</a>`;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle upload error
|
||||
xhr.addEventListener('error', () => {
|
||||
console.error('Upload error');
|
||||
});
|
||||
|
||||
xhr.send(formData);
|
||||
});
|
||||
</script>
|
||||
<div class="container">
|
||||
<h1 style="font-size: 72px; text-align: center; margin: 20px;"> <%= host %> </h1>
|
||||
<p style="text-align: center; font-size: 22px;"> <%= CONFIG.siteInfo %> </p>
|
||||
<div id="drop-area">
|
||||
<p style='padding: 0;margin: 0; color: #123718bf;'>Drop or Choose file(s)</p>
|
||||
<input type="file" id="fileElem" accept="*/*" style="display: none;">
|
||||
<!-- <label for="fileElem" class="button">Select File</label> -->
|
||||
</div>
|
||||
<div id="upload-status"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="text-align:center;">
|
||||
<p> <a href='./chatterino.png'>Chatterino Config</a> </p>
|
||||
<p> <a href='./sharex.sxcu'>ShareX Config</a> </p>
|
||||
<p> <a href='https://codeberg.org/Fijxu/file-uploader-crystal'>file-uploader-crystal (BETA <%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %> @ <%= CURRENT_BRANCH %>)</a> </p>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in a new issue