Skip to content

Commit

Permalink
Close #45
Browse files Browse the repository at this point in the history
  • Loading branch information
Ohswedd committed Nov 15, 2024
1 parent c762c48 commit 2e082fe
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 0 deletions.
243 changes: 243 additions & 0 deletions css/components/file-upload.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/* Base Styles */
.file-upload {
display: flex;
flex-direction: column;
gap: var(--space-4);
width: 100%;
max-width: clamp(320px, 80vw, 600px);
font-family: var(--font-sans);
color: var(--neutral-800);
/*background-color: var(--neutral-50);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-xl);*/
padding: var(--space-6);
transition: var(--transition-all);
}

.file-upload[data-variant="primary"] {
--file-upload-bg: var(--primary-light);
--file-upload-text: var(--primary-text);
--file-upload-border: var(--primary);
--file-upload-hover-bg: var(--primary-hover);
}

.file-upload[data-variant="secondary"] {
--file-upload-bg: var(--secondary-light);
--file-upload-text: var(--secondary-text);
--file-upload-border: var(--secondary);
--file-upload-hover-bg: var(--secondary-hover);
}

.file-upload[data-variant="accent"] {
--file-upload-bg: var(--accent-light);
--file-upload-text: var(--accent-text);
--file-upload-border: var(--accent);
--file-upload-hover-bg: var(--accent-hover);
}

.file-upload[data-variant="success"] {
--file-upload-bg: var(--success-light);
--file-upload-text: var(--success-text);
--file-upload-border: var(--success);
--file-upload-hover-bg: var(--success-hover);
}

.file-upload[data-variant="info"] {
--file-upload-bg: var(--info-light);
--file-upload-text: var(--info-text);
--file-upload-border: var(--info);
--file-upload-hover-bg: var(--info-hover);
}

.file-upload[data-variant="warning"] {
--file-upload-bg: var(--warning-light);
--file-upload-text: var(--warning-text);
--file-upload-border: var(--warning);
--file-upload-hover-bg: var(--warning-hover);
}

.file-upload[data-variant="danger"] {
--file-upload-bg: var(--danger-light);
--file-upload-text: var(--danger-text);
--file-upload-border: var(--danger);
--file-upload-hover-bg: var(--danger-hover);
}

/* Dropzone Styles */
.file-upload-dropzone {
display: flex;
align-items: center;
justify-content: center;
height: clamp(200px, 35vw, 320px);
background: var(--file-upload-bg) 60%;
border: 5px dashed var(--file-upload-border);
border-radius: var(--radius-lg);
text-align: center;
cursor: pointer;
position: relative;
overflow: hidden;
padding: var(--space-4);
transition: background-color 0.3s ease, border-color 0.3s ease, transform 0.2s ease;
box-shadow: var(--shadow-lg);
}

.file-upload-dropzone::after {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.95);
font-size: clamp(1rem, 1.5vw, 1.25rem);
color: var(--neutral-50); /* Brighter text for better contrast */
background-color: rgba(0, 0, 0, 0.2); /* Subtle overlay */
text-align: center;
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-lg);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
opacity: 0;
content: "Drop File to Upload";
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
z-index: 2;
}

.file-upload-dropzone:hover::after,
.file-upload-dropzone.dragging::after {
opacity: 1;
transform: translate(-50%, -50%) scale(1.05);
background-color: var(--file-upload-hover-bg);
color: var(--file-upload-text);
}

.file-upload-dropzone:hover,
.file-upload-dropzone:focus,
.file-upload-dropzone.dragging {
background-color: var(--file-upload-hover-bg);
border-color: var(--file-upload-border);
transform: scale(1.03);
cursor: copy;
position: relative;
overflow: hidden;
}

.file-upload-instructions {
font-size: clamp(1rem, 1.5vw, 1.25rem);
color: var(--neutral-900);
font-weight: 500;
text-align: center;
transition: opacity 0.3s ease, visibility 0.3s ease;
}

.file-upload-dropzone:hover ~ .file-upload-instructions,
.file-upload-dropzone.dragging ~ .file-upload-instructions {
opacity: 0;
visibility: hidden;
}

.file-upload-browse {
font-weight: bold;
color: var(--file-upload-text);
cursor: pointer;
text-decoration: underline;
transition: color 0.3s ease;
}

.file-upload-browse:hover {
color: var(--file-upload-border);
}

/* Hidden File Input */
.file-upload-input {
display: none;
}

/* File Details */
.file-upload-details {
display: flex;
flex-direction: column;
gap: var(--space-3);
animation: file-fadeIn 0.3s ease;
}

.file-upload-filename {
font-size: clamp(1rem, 1.2vw, 1.125rem);
color: var(--neutral-800);
word-break: break-word;
}

.file-upload-progress {
font-size: clamp(0.875rem, 1vw, 1rem);
color: var(--neutral-600);
display: inline-block;
margin-top: var(--space-1);
}

/* Multiple File Upload List */
.file-upload-list {
display: flex;
flex-direction: column;
gap: var(--space-2);
}

.file-upload-list-item {
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--neutral-100);
padding: var(--space-3);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
font-size: clamp(1rem, 1.2vw, 1.125rem);
transition: background-color 0.2s ease, transform 0.2s ease;
}

.file-upload-list-item:hover {
background-color: var(--neutral-200);
transform: translateY(-2px);
}

.file-upload-list-item button {
background: none;
border: none;
color: var(--danger);
font-size: 1.2rem;
cursor: pointer;
transition: color 0.2s ease;
}

.file-upload-list-item button:hover {
color: var(--danger-hover);
}

/* Animations */
@keyframes file-fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

/* Placeholder Animation for Dropzone */
.file-upload-dropzone-placeholder {
position: absolute;
font-size: clamp(1rem, 1.5vw, 1.25rem);
color: var(--neutral-600);
animation: file-fadeIn 0.3s ease-in-out;
}

/* Responsive Adjustments */
@media (max-width: 768px) {
.file-upload-dropzone {
height: clamp(150px, 30vw, 250px);
}

.file-upload-instructions {
font-size: clamp(0.875rem, 1.2vw, 1rem);
}

.file-upload {
padding: var(--space-3);
}
}
1 change: 1 addition & 0 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@
@import './components/stepper.css';
@import './components/calendar.css';
@import './components/navbar.css';
@import './components/file-upload.css';


33 changes: 33 additions & 0 deletions demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,39 @@ <h2 class="font-lg text-info my-4">Calendar with Events (November 2024)</h2>
</div>
</div>
</section>

<section class="p-6 bg-neutral-50 shadow-md rounded my-6">
<h2 class="text-lg text-primary mb-6">File Upload Component Showcase</h2>

<!-- Single File Upload -->
<div class="flex justify-center">
<div class="file-upload" data-variant="primary">
<div class="file-upload-dropzone" tabindex="0" aria-label="Drop a file or browse to upload">
<div class="file-upload-instructions">
<span class="file-upload-title">Upload a File</span><br />
Drag & Drop a File or <span class="file-upload-browse">Browse</span>
</div>
<input type="file" class="file-upload-input" />
</div>
<div class="file-upload-details">
<div class="file-upload-filename" aria-live="polite"></div>
<div class="file-upload-progress" aria-live="polite"></div>
</div>
</div>
</div>

<!-- Multiple File Upload -->
<div class="file-upload" data-variant="success" data-multiple="true">
<div class="file-upload-dropzone" tabindex="0" aria-label="Drop files or browse to upload multiple files">
<div class="file-upload-instructions">
<span class="file-upload-title">Upload Multiple Files</span><br />
Drag & Drop Files or <span class="file-upload-browse">Browse</span>
</div>
<input type="file" class="file-upload-input" multiple />
</div>
<div class="file-upload-list" aria-live="polite"></div>
</div>
</section>

</body>
<script type="module" src="js/main.js"></script>
Expand Down
64 changes: 64 additions & 0 deletions js/components/file-upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export function initializeFileUploadComponents() {
document.querySelectorAll('.file-upload').forEach((fileUpload) => {
const dropzone = fileUpload.querySelector('.file-upload-dropzone');
const input = fileUpload.querySelector('.file-upload-input');
const isMultiple = fileUpload.dataset.multiple === 'true';
const fileList = fileUpload.querySelector('.file-upload-list');
const fileNameDisplay = fileUpload.querySelector('.file-upload-filename');
const fileProgressDisplay = fileUpload.querySelector('.file-upload-progress');

dropzone.addEventListener('click', () => input.click());

input.addEventListener('change', (event) => {
const files = Array.from(event.target.files);
if (files.length === 0) return;

if (isMultiple && fileList) {
fileList.innerHTML = '';
files.forEach((file) => appendFileToList(file, fileList));
} else if (fileNameDisplay && fileProgressDisplay) {
const file = files[0];
fileNameDisplay.textContent = file.name;
fileProgressDisplay.textContent = 'Ready to upload';
}
});

dropzone.addEventListener('dragover', (event) => {
event.preventDefault();
dropzone.classList.add('dragging');
});

dropzone.addEventListener('dragleave', () => {
dropzone.classList.remove('dragging');
});

dropzone.addEventListener('drop', (event) => {
event.preventDefault();
dropzone.classList.remove('dragging');
const files = Array.from(event.dataTransfer.files);
input.files = event.dataTransfer.files;

if (isMultiple && fileList) {
fileList.innerHTML = '';
files.forEach((file) => appendFileToList(file, fileList));
} else if (fileNameDisplay && fileProgressDisplay) {
const file = files[0];
fileNameDisplay.textContent = file.name;
fileProgressDisplay.textContent = 'Ready to upload';
}
});

function appendFileToList(file, listContainer) {
const listItem = document.createElement('div');
listItem.className = 'file-upload-list-item';
listItem.innerHTML = `
<span>${file.name}</span>
<button aria-label="Remove file">&times;</button>
`;
listItem.querySelector('button').addEventListener('click', () => {
listItem.remove();
});
listContainer.appendChild(listItem);
}
});
}
4 changes: 4 additions & 0 deletions js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Slideshow } from './components/slideshow.js';
import { initializeRatingComponents } from './components/rating.js';
import { initializeCalendarComponents } from './components/calendar.js';
import { Navbar } from './components/navbar.js';
import { initializeFileUploadComponents } from './components/file-upload.js';

document.addEventListener("DOMContentLoaded", () => {
// Initialize rating components
Expand All @@ -18,6 +19,9 @@ document.addEventListener("DOMContentLoaded", () => {
// Initialize calendar components
initializeCalendarComponents();

// Initialize file upload components
initializeFileUploadComponents();

// Initialize other components, if applicable
document.querySelectorAll('.alert .alert-close').forEach(button => {
button.addEventListener('click', event => {
Expand Down

0 comments on commit 2e082fe

Please sign in to comment.