From 8e1ef327a2cb4ca8b0cbf4aa7a4baa65388fb70d Mon Sep 17 00:00:00 2001 From: prakash meena Date: Thu, 4 Jun 2026 17:48:36 +0530 Subject: [PATCH] feat: add Drag-and-Drop File Upload Component (#1201) --- submissions/examples/file-upload/README.md | 37 ++++ submissions/examples/file-upload/demo.html | 139 +++++++++++++++ submissions/examples/file-upload/style.css | 187 +++++++++++++++++++++ 3 files changed, 363 insertions(+) create mode 100644 submissions/examples/file-upload/README.md create mode 100644 submissions/examples/file-upload/demo.html create mode 100644 submissions/examples/file-upload/style.css diff --git a/submissions/examples/file-upload/README.md b/submissions/examples/file-upload/README.md new file mode 100644 index 00000000..2d368c80 --- /dev/null +++ b/submissions/examples/file-upload/README.md @@ -0,0 +1,37 @@ +# File Upload Component + +A drag-and-drop file upload zone with distinct animated states: idle, drag-over, uploading (indeterminate progress bar), success (checkmark pop), and error (shake). Includes file type validation and size checking with inline JavaScript. + +## Classes + +| Class | Description | +|---|---| +| `ease-file-upload` | Main container (click to browse, drag target) | +| `ease-file-upload--drag-over` | File hovering over the drop zone | +| `ease-file-upload--uploading` | Upload in progress | +| `ease-file-upload--success` | Upload completed successfully | +| `ease-file-upload--error` | Upload failed | +| `ease-upload-icon` | State icon (upload arrow / check / error) | +| `ease-upload-text` | State description text | +| `ease-upload-hint` | Supported file types hint | +| `ease-upload-progress` | Progress bar track | +| `ease-upload-progress-bar` | Animated indeterminate progress fill | + +## Usage + +```html +
+ ... + Drag & drop files here or click to browse + Supports PNG, JPG, WebP, PDF (max 5MB) +
+
+
+
+``` + +A minimal JS setup handles drag events, file validation, and state transitions (see `demo.html`). + +## Why it fits EaseMotion CSS + +Five animated visual states with smooth transitions, floating icon animation, indeterminate progress bar, pop-in checkmark, and error shake — all using `ease-` prefixed keyframes. Respects `prefers-reduced-motion`. diff --git a/submissions/examples/file-upload/demo.html b/submissions/examples/file-upload/demo.html new file mode 100644 index 00000000..8c97bd75 --- /dev/null +++ b/submissions/examples/file-upload/demo.html @@ -0,0 +1,139 @@ + + + + + + File Upload — EaseMotion CSS + + + + +
+ + + + + + Drag & drop files here or click to browse + Supports PNG, JPG, WebP, PDF (max 5MB) +
+
+
+
+ + + + + diff --git a/submissions/examples/file-upload/style.css b/submissions/examples/file-upload/style.css new file mode 100644 index 00000000..60cfeda4 --- /dev/null +++ b/submissions/examples/file-upload/style.css @@ -0,0 +1,187 @@ +/* ============================================================ + EaseMotion CSS — Drag-and-Drop File Upload Component + Issue #1201 + ============================================================ */ + +/* ── Container ────────────────────────────────────────────── */ + +.ease-file-upload { + max-width: 480px; + margin: 2rem auto; + border: 2px dashed rgba(255, 255, 255, 0.15); + border-radius: var(--ease-radius-lg, 0.875rem); + padding: 2.5rem 2rem; + text-align: center; + cursor: pointer; + background: rgba(255, 255, 255, 0.02); + transition: + border-color var(--ease-speed-normal, 250ms) cubic-bezier(0.4, 0, 0.2, 1), + background var(--ease-speed-normal, 250ms) cubic-bezier(0.4, 0, 0.2, 1), + transform var(--ease-speed-fast, 150ms) cubic-bezier(0.4, 0, 0.2, 1), + box-shadow var(--ease-speed-normal, 250ms) cubic-bezier(0.4, 0, 0.2, 1); + outline: none; +} + +.ease-file-upload:hover { + border-color: rgba(124, 108, 255, 0.4); + background: rgba(124, 108, 255, 0.04); +} + +.ease-file-upload:focus-visible { + box-shadow: 0 0 0 3px rgba(124, 108, 255, 0.3); +} + +/* ── Icon ─────────────────────────────────────────────────── */ + +.ease-upload-icon { + display: block; + margin: 0 auto 1rem; + color: rgba(255, 255, 255, 0.3); + transition: color var(--ease-speed-normal, 250ms) cubic-bezier(0.4, 0, 0.2, 1); +} + +/* ── Text ─────────────────────────────────────────────────── */ + +.ease-upload-text { + display: block; + font-size: var(--ease-text-sm, 0.9375rem); + color: rgba(255, 255, 255, 0.7); + margin-bottom: 0.375rem; + font-weight: 500; +} + +.ease-upload-hint { + display: block; + font-size: var(--ease-text-xs, 0.75rem); + color: rgba(255, 255, 255, 0.35); +} + +/* ── State: drag-over ─────────────────────────────────────── */ + +.ease-file-upload--drag-over { + border-color: #7c6cff; + border-style: solid; + background: rgba(124, 108, 255, 0.08); + transform: scale(1.02); + box-shadow: 0 0 0 4px rgba(124, 108, 255, 0.12); +} + +.ease-file-upload--drag-over .ease-upload-icon { + color: #7c6cff; + animation: ease-kf-upload-float 1s ease-in-out infinite; +} + +/* ── State: uploading ─────────────────────────────────────── */ + +.ease-file-upload--uploading { + pointer-events: none; + opacity: 0.8; + border-color: #7c6cff; + border-style: solid; +} + +.ease-file-upload--uploading .ease-upload-icon { + color: #7c6cff; + animation: ease-kf-upload-pulse 1.2s ease-in-out infinite; +} + +/* ── State: success ───────────────────────────────────────── */ + +.ease-file-upload--success { + border-color: #22c55e; + border-style: solid; + background: rgba(34, 197, 94, 0.05); +} + +.ease-file-upload--success .ease-upload-icon { + color: #22c55e; + animation: ease-kf-upload-pop-check 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +/* ── State: error ─────────────────────────────────────────── */ + +.ease-file-upload--error { + border-color: #ef4444; + border-style: solid; + background: rgba(239, 68, 68, 0.05); + animation: ease-kf-upload-shake 0.4s cubic-bezier(0.36, 0.07, 0.19, 0.97); +} + +.ease-file-upload--error .ease-upload-icon { + color: #ef4444; +} + +/* ── Progress bar ─────────────────────────────────────────── */ + +.ease-upload-progress { + display: none; + height: 5px; + border-radius: 3px; + background: rgba(255, 255, 255, 0.08); + margin-top: 1.25rem; + overflow: hidden; +} + +.ease-file-upload--uploading .ease-upload-progress { + display: block; +} + +.ease-upload-progress-bar { + height: 100%; + width: 0%; + border-radius: 3px; + background: linear-gradient(90deg, #7c6cff, #a78bfa); + animation: ease-kf-upload-progress-indeterminate 1.5s ease-in-out infinite; +} + +/* ── Keyframes ────────────────────────────────────────────── */ + +@keyframes ease-kf-upload-float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-6px); } +} + +@keyframes ease-kf-upload-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + +@keyframes ease-kf-upload-pop-check { + 0% { transform: scale(0); } + 50% { transform: scale(1.3); } + 100% { transform: scale(1); } +} + +@keyframes ease-kf-upload-shake { + 0%, 100% { transform: translateX(0); } + 20% { transform: translateX(-8px); } + 40% { transform: translateX(8px); } + 60% { transform: translateX(-6px); } + 80% { transform: translateX(6px); } +} + +@keyframes ease-kf-upload-progress-indeterminate { + 0% { width: 0%; margin-left: 0; } + 50% { width: 50%; margin-left: 25%; } + 100% { width: 0%; margin-left: 100%; } +} + +/* ── Reduced motion ──────────────────────────────────────── */ + +@media (prefers-reduced-motion: reduce) { + .ease-file-upload--drag-over { + transform: none; + } + .ease-file-upload--drag-over .ease-upload-icon, + .ease-file-upload--uploading .ease-upload-icon, + .ease-file-upload--success .ease-upload-icon { + animation: none; + } + .ease-file-upload--error { + animation: none; + } + .ease-upload-progress-bar { + animation: none; + width: 50%; + } +}