mirror of
https://github.com/DumbWareio/DumbDrop.git
synced 2025-10-25 00:53:53 +00:00
Initial Commit
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
uploads/*
|
||||||
|
.env
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -128,3 +128,5 @@ dist
|
|||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
uploads/
|
||||||
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN mkdir -p uploads
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
1030
package-lock.json
generated
Normal file
1030
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "dumbdrop",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "A simple file upload application",
|
||||||
|
"dependencies": {
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^16.0.3",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"multer": "^1.4.5-lts.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
128
public/index.html
Normal file
128
public/index.html
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dumb Drop - Simple File Upload</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Dumb Drop</h1>
|
||||||
|
<div class="upload-container" id="dropZone">
|
||||||
|
<div class="upload-content">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||||
|
<polyline points="17 8 12 3 7 8"/>
|
||||||
|
<line x1="12" y1="3" x2="12" y2="15"/>
|
||||||
|
</svg>
|
||||||
|
<p>Drag and drop files here<br>or</p>
|
||||||
|
<input type="file" id="fileInput" multiple hidden>
|
||||||
|
<button onclick="document.getElementById('fileInput').click()">Browse Files</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="fileList" class="file-list"></div>
|
||||||
|
<button id="uploadButton" class="upload-button" style="display: none;">Upload Files</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const dropZone = document.getElementById('dropZone');
|
||||||
|
const fileInput = document.getElementById('fileInput');
|
||||||
|
const fileList = document.getElementById('fileList');
|
||||||
|
const uploadButton = document.getElementById('uploadButton');
|
||||||
|
let files = [];
|
||||||
|
|
||||||
|
// Prevent default drag behaviors
|
||||||
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||||
|
dropZone.addEventListener(eventName, preventDefaults, false);
|
||||||
|
document.body.addEventListener(eventName, preventDefaults, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highlight drop zone when dragging over it
|
||||||
|
['dragenter', 'dragover'].forEach(eventName => {
|
||||||
|
dropZone.addEventListener(eventName, highlight, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
['dragleave', 'drop'].forEach(eventName => {
|
||||||
|
dropZone.addEventListener(eventName, unhighlight, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle dropped files
|
||||||
|
dropZone.addEventListener('drop', handleDrop, false);
|
||||||
|
fileInput.addEventListener('change', handleFiles, false);
|
||||||
|
uploadButton.addEventListener('click', uploadFiles);
|
||||||
|
|
||||||
|
function preventDefaults(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlight(e) {
|
||||||
|
dropZone.classList.add('highlight');
|
||||||
|
}
|
||||||
|
|
||||||
|
function unhighlight(e) {
|
||||||
|
dropZone.classList.remove('highlight');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(e) {
|
||||||
|
files = [...e.dataTransfer.files];
|
||||||
|
updateFileList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFiles(e) {
|
||||||
|
files = [...e.target.files];
|
||||||
|
updateFileList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFileList() {
|
||||||
|
fileList.innerHTML = '';
|
||||||
|
files.forEach(file => {
|
||||||
|
const fileItem = document.createElement('div');
|
||||||
|
fileItem.className = 'file-item';
|
||||||
|
fileItem.textContent = `${file.name} (${formatFileSize(file.size)})`;
|
||||||
|
fileList.appendChild(fileItem);
|
||||||
|
});
|
||||||
|
uploadButton.style.display = files.length > 0 ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFileSize(bytes) {
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadFiles() {
|
||||||
|
const formData = new FormData();
|
||||||
|
files.forEach(file => {
|
||||||
|
formData.append('files', file);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
uploadButton.disabled = true;
|
||||||
|
uploadButton.textContent = 'Uploading...';
|
||||||
|
|
||||||
|
const response = await fetch('/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
alert(result.message);
|
||||||
|
|
||||||
|
// Reset the form
|
||||||
|
files = [];
|
||||||
|
updateFileList();
|
||||||
|
uploadButton.textContent = 'Upload Files';
|
||||||
|
} catch (error) {
|
||||||
|
alert('Error uploading files');
|
||||||
|
console.error('Error:', error);
|
||||||
|
} finally {
|
||||||
|
uploadButton.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
118
public/styles.css
Normal file
118
public/styles.css
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 40px 20px;
|
||||||
|
border: 2px dashed #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-container.highlight {
|
||||||
|
border-color: #4CAF50;
|
||||||
|
background: #f0f9f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-content svg {
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-content p {
|
||||||
|
color: #666;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #45a049;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background: #cccccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-list {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-item {
|
||||||
|
background: white;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: left;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-button {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 200px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-container {
|
||||||
|
padding: 20px 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
server.js
Normal file
38
server.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const multer = require('multer');
|
||||||
|
const path = require('path');
|
||||||
|
const cors = require('cors');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
const uploadDir = process.env.UPLOAD_DIR || 'uploads';
|
||||||
|
|
||||||
|
// Configure multer for file upload
|
||||||
|
const storage = multer.diskStorage({
|
||||||
|
destination: (req, file, cb) => {
|
||||||
|
cb(null, uploadDir);
|
||||||
|
},
|
||||||
|
filename: (req, file, cb) => {
|
||||||
|
cb(null, `${Date.now()}-${file.originalname}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const upload = multer({ storage: storage });
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
app.post('/upload', upload.array('files'), (req, res) => {
|
||||||
|
if (!req.files || req.files.length === 0) {
|
||||||
|
return res.status(400).json({ message: 'No files uploaded' });
|
||||||
|
}
|
||||||
|
res.json({ message: 'Files uploaded successfully' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user