Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save toomanyredirects/4f6e27a970d391cc2b935f656c95a8e4 to your computer and use it in GitHub Desktop.
Save toomanyredirects/4f6e27a970d391cc2b935f656c95a8e4 to your computer and use it in GitHub Desktop.
HTML5 Drag & Drop File Input
<body>
<main id="content" role="main">
<h1>HTML5 <code>&lt;input type="file"/&gt;</code></h1>
<p>
A <b>HTML5 file input</b> variations normalized with Javascript and SCSS as a <abbr title="Progressive enhancement is a strategy for web design that emphasizes core webpage content first. This strategy then progressively adds more nuanced and technically rigorous layers of presentation and features on top of the content as the end-user's browser/internet connection allow.">progressive enhancement</abbr> with cross-browser support.
</p>
<p>
<!-- Example code -->
<i class="loading ellipsis" data-loading="loading"></i>
<!-- Example code / -->
</p>
<section>
<!-- Upload file - Code example 1 -->
<form action="" method="post" enctype="multipart/form-data" >
<fieldset class="upload dropzone" data-dropzone="Drop file here...">
<input id="file-upload" type="file" accept="image/*,.pdf" required />
<label for="file-upload" data-label="Select a file:"></label>
<ul class="preview" data-empty="Drag or browse for a file."></ul>
<label for="file-upload" class="icon file" title="Browse"></label>
<description class="info"></description>
<em class="error"
data-nosupport="File API not supported."
data-nofile="No file selected."
data-required="Mandatory file upload."
data-count="Only one file allowed."
data-mime="Allowed files types: "></em>
</fieldset>
</form>
<!-- / Upload file - Code example 1 -->
<!-- Uplad multiple - Code example 2 -->
<form action="" method="post" enctype="multipart/form-data">
<fieldset class="upload upload-multiple dropzone" data-dropzone="Drop files & folders here...">
<input id="multi-upload" type="file" accept="*" multiple directory required />
<label for="multi-upload" data-label="Select files & folders:"></label>
<ul class="preview" data-empty="Drag or browse for files & folders."></ul>
<i class="icon cloud" title="Upload files"></i>
<em class="error"
data-nosupport="File API not supported."
data-nofile="No file selected."
data-required="Mandatory file upload."
data-count="Only 100 simultaneous files allowed."
data-mime="Allowed files types: "></em>
</fieldset>
</form>
<!-- / Uplad multiple - Code example 2 -->
<!-- Upload photo booth - Code example 3 -->
<form action="" method="post" enctype="multipart/form-data">
<fieldset class="upload upload-photo dropzone" data-dropzone="Drop image here...">
<input id="image-upload" type="file" accept="image/*,capture=camera" capture="user" required />
<label for="image-upload" data-label="Browse for files..."></label>
<ul class="preview circle" data-empty="Drag or browse for an image."></ul>
<i class="icon camera" title="Camera" data-video="Click to record." data-recording="Recording..."></i>
<description class="info"></description>
<em class="error"
data-nosupport="File API not supported."
data-nofile="No file selected."
data-required="Mandatory file upload."
data-count="Only one file allowed."
data-mime="Allowed files types: "></em>
</fieldset>
</form>
<!-- / Upload photo booth - Code example 3 -->
</section>
</main>
</body>
/* Drag & drop file input and input normalization */
fileInput = function(elements){
var selectors = elements || 'input[type="file"]',
imgRegx = /\.(jpe?g|png|svg|webp|bmp|gif)$/i;
document.querySelectorAll(selectors).forEach( function(input){
var dropzone = input.form.querySelector('.dropzone') || document.body || document.documentElement.body,
parent = input.parentElement,
preview = parent.querySelector('.preview'),
isCapture = input.accept.match(/capture.*/g) || input.getAttribute('capture');
/* Event listeners */
dropzone.ondragover = function(e) { onDrag(e, dropzone); };
dropzone.ondragleave = function(e) { onDrag(e, dropzone); };
dropzone.ondrop = function(e) { onDrop(e, input, preview, dropzone); };
input.onchange = function(e) { onDrop(e, input, preview, dropzone); };
if(isCapture)
input.parentElement.querySelector('.camera').onclick = function(e) {capturing(e, preview, input);};
}
);
/* Drag & drop functions */
function onDrag (e, dropzone) {
// e = e || window.event;get window.event if e argument missing (in IE)
e.stopPropagation();
e.preventDefault();
if (e.type === 'dragover') dropzone.classList.add('dragover');
else dropzone.classList.remove('dragover');
}
/* Drop & error handling function */
function onDrop (e, input, preview, dropzone) {
onDrag(e, dropzone);
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {// Check File API support
return showError(input, 'nosupport', 'fileapi');
}
var files = e.target.files || e.currentTarget.files || e.dataTransfer.files ,
// folders = e.target.items || e.dataTransfer.items,
folders = (e.dataTransfer) ? e.dataTransfer.items : false,
accept = input.accept || '*',
acceptRegx = accept.split(',') || accept.split(';') || accept;
input.files = files;
if(folders && input.multiple){
for(var i = 0; i < folders.length; i++) {
var dir = folders[i].webkitGetAsEntry();
if (dir) directoryIterator(dir, null, preview);
}
return; // break further files processing
}
/* Preview handling */
if (files.length === 1) {
if(!input.multiple){
reset(preview); // Reset prior previews
if(input.parentElement.className.indexOf('upload-photo') > -1 && accept.match(/image.*/g))
createPreview(files[0], preview, true, true);
else if (!files[0].type.match(accept))
return showError(input, 'mime', accept);
else
createPreview(files[0], preview, true);
} else {
createPreview(files[0], preview);
}
} else if (files.length > 1) {
if (!input.multiple) {
return showError(input, 'count');
} else {
for(var i = 0; i < files.length; i++)
createPreview(files[i], preview);
}
} else {
return showError(input, 'nofile');
}
}
/* Error function */
function showError(input, attribute, msg) {
var error = input.parentElement.querySelector('.error'),
data = input.parentElement.querySelector('[data-'+ attribute +']'),
msg = (data) ? data.getAttribute('data-'+ attribute) + (msg || '')
: 'Error'+ attribute +': '+ (msg || '');
error.innerHTML = msg;
input.parentElement.classList.add('hasError');
}
/* Create a preview item */
function createPreview(file, preview, isSingle, isImage) {
var reader = new FileReader(),
img = new Image(),
item = document.createElement('li'),
btnRemove = document.createElement('i');
btnRemove.onclick = function(e){ remove(btnRemove, preview); };
reader.addEventListener("load", function () {
img.title = file.name;
img.alt = 'size: '+ file.size +', type: '+ file.type +', modified: '+ file.lastModified;
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
item.innerHTML = '<b>'+ file.name +'</b><small data-upload="0">'+ formatBytes(file.size) +' '+ file.type +'</small>';
if (file.name.match(imgRegx)) {
img.style.backgroundImage = 'url('+ reader.result +')';
if(isSingle && isImage) preview.style.backgroundImage = 'url('+ reader.result +')';
}
item.insertAdjacentElement('beforeend', btnRemove);
item.insertAdjacentElement('afterbegin', img);
item.addEventListener('click', function(e){ upload(e, item, file); }, false);
preview.appendChild(item);
}, false);
reader.readAsDataURL(file);
}
/* Camera capture */
function capturing(e, preview, input){
navigator.mediaDevices.getUserMedia({ video:true })
.then(function(stream) {
var video = document.createElement('video'),
control = preview.parentElement.querySelector('.camera'),
title = control.title || 'Camera',
recording = control.getAttribute('data-recording') || 'Recording...',
shutter = new Audio('https://www.soundjay.com/mechanical/camera-shutter-click-01.mp3'),
canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
w, h, ratio;
reset(preview); // Reset prior previews
preview.classList.remove('snaphot'); // Reset prior snapshots
preview.appendChild(video);
/* Recording button */
control.classList.add('recording'); control.title = recording;
control.onclick = function(){
reset(preview); this.title = title;
this.classList.remove('recording');
};
/* Camera input stream */
video.srcObject = stream;
video.addEventListener('loadedmetadata', function() {
ratio = video.videoWidth/video.videoHeight;
w = video.videoWidth-100;
h = parseInt(w/ratio,10);
canvas.width = w;
canvas.height = h;
video.play();
},false);
// video.style.zIndex = 1000;
control.addEventListener('click', function(e) {
e.preventDefault();
// e.stopPropagation();
ctx.fillRect(0, 0, w, h);
ctx.drawImage(video, 0, 0, w, h);
var blob = canvas.toDataURL('image/jpeg'),
now = new Date(),
created = now.toLocaleDateString('de-CH') +' at '+ now.toLocaleTimeString('de-CH');
shutter.play();
preview.classList.add('snaphot');
reset(preview); control.title = title;
item = document.createElement('li');
item.innerHTML = '<b>Snapshot</b><small data-upload="0">'+ created +'</small><i><i/>';
preview.appendChild(item);
preview.style.backgroundImage = 'url('+ blob +')';
}, false);
})
.catch(function(err) {
showError(input, 'capture', err.name + ": " + err.message);
});
}
/* Clear / empty the preview element and reset all controls */
function reset(el) {
el.parentElement.classList.remove('hasError'); /* Reset possible errors */
el.innerHTML = ''; el.style.backgroundImage = '';
el.parentElement.querySelector('.icon').classList.remove('recording');
fileInput();
}
/* Remove fileElement from dom and fileList */
function remove(el, preview) {
preview.removeChild(el.parentElement);
}
function upload(e, item, file) {
e.preventDefault();
item.classList.add('uploading');
item.addEventListener('click', function(){
item.classList.remove('uploading');
item.classList.add('uploaded');
}, false);
/*
var data = new FormData();
data.append('files', file);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'handler.cfm', true);
xhr.onload = function(e) {
if(this.status == 200)
console.log(e.currentTarget.responseText || e.target.responseText);
else
alert('Upload error');
}
xhr.send(data);*/
}
/* Format bytes to KB, MB */
function formatBytes(number) {
if(number < 1024) return number + 'bytes';
else if (number >= 1024 && number < 1048576) return (number/1024).toFixed(1) + 'KB';
else if (number >= 1048576) return (number/1048576).toFixed(1) + 'MB';
}
/* Directory traversing function */
function directoryIterator(item, path, preview) {
path = path || ''; preview = preview || '';
if (item.isFile) { // Get file
item.file(function(file) {
// console.log("File:", path + file.name);
createPreview(file, preview);
});
} else if (item.isDirectory) { // Get folder contents
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
for (var i=0; i<entries.length; i++) {
directoryIterator(entries[i], path + item.name + "/", preview);
}
});
}
}
};
// Initiate file inputs
// For special element selection: fileInput('.elements, elements, #element');
fileInput();
@charset "utf-8";
// Default SCSS layout variables for example
// -----------------------------------------
// Google font import
@import url(https://fonts.googleapis.com/css?family=Raleway:200,400,500,800);
// Core colors
$primary-color: #5755d9 !default;
$primary-color-dark: darken($primary-color, 5%) !default;
$primary-color-light: lighten($primary-color, 4%) !default;
$secondary-color: lighten($primary-color, 37.5%) !default;
$secondary-color-dark: darken($secondary-color, 3%) !default;
$secondary-color-light: lighten($secondary-color, 3%) !default;
$highlight-color: #ffe9b3 !default;
// Dark / gray colors
$dark-color: #303742 !default;
$light-color: #fff !default;
$gray-color: lighten($dark-color, 55%) !default;
$gray-color-dark: darken($gray-color, 30%) !default;
$gray-color-light: lighten($gray-color, 20%) !default;
// Border radius
$border-radius: .2rem !default;
// Control colors
$success-color: #32b643 !default;
$warning-color: #ffb700 !default;
$error-color: #e85600 !default;
// Responsive breakpoints
$size-xxs: 380px !default;
$size-xs: 480px !default;
$size-sm: 600px !default;
$size-md: 840px !default;
$size-lg: 960px !default;
$size-xl: 1280px !default;
$size-2x: 1440px !default;
$responsive-breakpoint: $size-xs !default;
$responsive-breakpoint-md: $size-md !default;
// Z-index
$zindex-0: 1 !default;
$zindex-1: 100 !default;
$zindex-2: 200 !default;
$zindex-3: 300 !default;
$zindex-4: 400 !default;
// Layout
$layout-spacing: 1rem !default;
// base64 url encode hex color. Use: #{url-colour($primary-color)}
@function url-color($color) {
@return '%23' + str-slice('#{$color}', 2, -1)
}
// HTML5 file input frag & drop file / direcory upload
// Input File SCSS code
// ------------------------------------------
// Note: No vendor prefixes added!
$upload-accent-color: $primary-color !default;
$upload-dropzone-bgcolor: rgba(0,0,0,.5) !default;
$upload-info-bgcolor: rgba(0,0,0,.75) !default;
$upload-info-fontcolor: $light-color !default;
$upload-icon-color: $light-color !default;
// Print Backgrounds in Chrome / Safari
@media print {
#container * {
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
}
/* ------Basic reset-------- */
*,*::after,*::before {
margin:0;
padding:0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html * {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
scroll-behavior: smooth;
}
// HTML5 file input upload
// with profile pic photo booth
// Animations
@keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(25%);}
100% { transform: translateY(0); }
}
@keyframes recording {
0% { transform: scale(1); background-color: currentColor; }
50% { transform: scale(.85); background-color: transparent;}
100% { transform: scale(1); background-color: currentColor; }
}
@keyframes flash {
0% { opacityr: 1; }
100% { opacityr: 0; }
}
// Disable selection document-wide
html {
user-select: none; // prevent selecting elements on drag
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
// HTML5 file input drag & drop file / direcory upload
// Loading ellipsis extends unitUX .loading module
.loading {
&.ellipsis {
width:auto; height: inherit;
display:inline-block; // needs to be set for non block elements
animation: none;
white-space: nowrap;
font-size: 1em;
font-style: normal;
cursor: progress;
&::first-letter {
text-transform: uppercase;
}
&::before{ // Check for available properties and insert
content: attr(data-loading);
content: 'loading'; // en-US as fallback (missing data-* property)
display:inline; // Nedds to be set inline, otherways make ::first-letter not to render
-webkit-animation: none; // Unset .loading module's prior animation
animation: none;
}
&::after {
content: '\2026'; // Ascii code for the ellipsis character
overflow: hidden;
display: inline-block;
vertical-align: bottom;
box-sizing:content-box;
width: 0;
text-align:left;
margin-right: 1.25em;
-webkit-animation: ellipsis steps(4, end) 2s infinite;
animation: ellipsis steps(4, end) 2s infinite;
}
}
}
@-webkit-keyframes ellipsis {
to { width: 1.25em; margin-right:0;}
}
@keyframes ellipsis {
to { width: 1.25em; margin-right:0;}
}
// Dropzone
.dropzone {
// Droppable hover
&.dragover {
pointer-events: all;
z-index: $zindex-4; // Highest index
position: relative;
color:$upload-info-fontcolor;
& * , & *:empty {
z-index:$zindex-0;
&::after, &::before {
pointer-events: none;
z-index:$zindex-0;
}
}
&::before, &::after {
content: '';
z-index:$zindex-1;
pointer-events: none;
position: absolute;
display:inline;
}
&::before {
content: attr(data-dropzone);
text-shadow: 0 1px 1px rgba(0, 0, 0, .75);
left: 0; top: 0; bottom: 0;
width: 100%; height:100%; max-height:100%;
background-color: $upload-dropzone-bgcolor;
padding-top: 35%;
overflow:hidden;
}
&::after {
top: 35%; left: 50%;
margin: -2.5em;
width: 5em; height: 5em;
background: transparent no-repeat center center;
background-size: contain;
background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="#{url-color($upload-icon-color)}"%3E%3Cpath d="M51.7 26.7a20 20 0 0 0-19.7-16c-7.7 0-14.4 4.3-17.6 10.7A16 16 0 0 0 16 53.3h34.7C58.1 53.3 64 47.5 64 40c0-6.9-5.6-12.8-12.3-13.3zm-14.4 8v10.7H26.7V34.7h-8L32 21.3l13.3 13.3h-8z"/%3E%3C/svg%3E');
animation: 1.5s bounce infinite;
}
label {
z-index:$zindex-3;
}
.preview {
pointer-events: none;
transform: scale(.7);
filter: blur(3px);
opacity:.2;
transition: all 250ms ease-in-out;
&:empty::after{
content: '';
}
}
}
}
// HTML5 form input file
// Upload class on parent fieldset / .input-group
.upload {
font-size: 1rem; // Sizing scale for 1em in the selector
color: $upload-info-fontcolor;
margin: 0 auto; padding: 0;
margin-top:2em;
position: relative;
width: 100%;
border: 0;
display: block;
// Hover state of icon (camer, cloud, folder)
&:hover {
& .icon {
transform: scale(.8);
&.cloud{
transform: scale(.8) translate(-50%, 10%);
}
}
}
input[type="file"] {
position: absolute;
width: 0; height:0;
opacity: 0;
}
& label:not(.icon) {
position: absolute; display: block;
bottom: 0; margin: 0; padding: 0;
width: 100%; height:100%;
cursor: pointer;
pointer-events: all;
&::before {
z-index:$zindex-1;
}
&:after {
position: absolute; display: block;
content: attr(data-label);
left: 0; bottom: auto!important; top:-2em;
width: 100%; height: 1em;
padding: 0;
text-align:left;
text-shadow: 0 1px 1px $upload-info-bgcolor;
}
}
.icon {
position: absolute; display:block; overflow:visible;
bottom: .25em; right: .5em;
width:1em; height:1em;
pointer-events:all;
cursor:pointer;
transform: scale(1);
filter: drop-shadow(1px 1px 1px $upload-info-bgcolor);
transition: transform .25s ease;
font-size: 2em; font-style:normal;
&::before{
content: url('data:image/svg+xml;charset=utf-8,%3Csvg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60" fill="#{url-color($upload-icon-color)}"%3E%3Cpath d="M14 24h-1L2 53v1l1 1h44l3-2 10-28v-1H14z"/%3E%3Cpath d="M13 22h41v-7c0-1-1-3-3-3H27l-5-6H3C1 6 0 7 0 8v42l10-27 3-1z"/%3E%3C/svg%3E');
}
}
.preview {
margin:0; padding:0;
list-style:none;
text-align:left;
position:relative;
min-height:3em;
background: no-repeat center center;
background-size: contain;
-o-object-fit: contain;
object-fit: contain;
&:empty{
pointer-events:none;
&::after{
position:absolute; display:block;
content: attr(data-empty);
top:50%; left:0; width:100%;
transform:translateY(-50%);
}
}
li {
display:inline-block; box-sizing:border-box;
overflow:hidden; position: relative;
margin:0 2em 0 0; padding:.5em;
padding-right: 5.75em;
white-space: nowrap;
border-radius: $border-radius;
left:0; right:0; top:0;
width:100%;
min-height:3em;
line-height:1.1;
text-align: top;
vertical-align:top;
&.uploading {
small {
position:relative;
text-indent:100%; height: .5em; margin-top:.6em; // Total: 1.1em
background-color: rgba($upload-icon-color, .25);
background-image: linear-gradient(to right, $upload-accent-color 50%, transparent 50%);
&::after {
content: attr(data-upload);
position:absolute; display: block;
text-align: right;
right:0; top: -1.1em;
}
}
i:last-of-type::before{
content: none;
}
}
&.uploaded {
}
img {
position: relative; display:block;
width:2em; height:2em;
margin:0 .75em 0 0;
float:left;
border: .25em solid white;
background: white no-repeat center center;
background-size: 100% auto;
background-size: contain;
-o-object-fit: contain;
object-fit: contain;
}
b, small {
display: block; overflow: hidden;
text-overflow: ellipsis;
}
b{
font-weight: 600;
}
small{
height:1.1em; // For upload progree bar in multiple
opacity:.7;
}
i{
z-index:$zindex-1;
position:relative; display:inline-block;
float:right; top:-1.75em; right:-2.75em;
width: 2em; height: 0;
background-color:transparent;
&::before{
position:absolute; display:block;
width: 1.7em; height: 1.7em;
margin:0; padding:.3em;
-o-object-fit: contain;
object-fit: contain;
border-radius: 50%;
cursor:pointer; pointer-events:all;
opacity:.75;
// transform: scale(.75);
}
&:last-of-type::before{
content: url('data:image/svg+xml;charset=utf-8,%3Csvg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 124 124"%3E%3Cpath d="M16 105l89-89M16 16l89 89" stroke="#{url-color($upload-icon-color)}" stroke-width="15"/%3E%3C/svg%3E');
}
&:hover, &:focus, &:active{
&::before{
background-color:$error-color;
opacity:1;
}
}
}
}
}
.error {
position:absolute; display:block; overflow: visible;
top:-2em; left:50%;
transform: translate(-50%, -1em);
background-color:$error-color;
border-radius: $border-radius;
padding: .5em .75em;
color: white;
font-style: normal;
text-align:center;
opacity:0;
visibility: hidden;
pointer-events: none;
filter: drop-shadow(0 .73em .5em rgba(0,0,0,.25));
transition: opacity .25s ease-in-out;
&::after{
content: ''; display: block; position: absolute;
width: .35; height: .35;
left:50%; bottom: -.7em;
border: .325em solid transparent;
border-width: .35em;
border-color: transparent transparent transparent $error-color;
transform: rotate(90deg) translateY(50%);
}
}
// Errors
&.hasError {
.error {
opacity:1;
visibility: visible;
}
}
// Multiple file & folder upload
&.upload-multiple{
counter-reset: file-count;
label{
display:block;
border: 1px dashed currentcolor;
border-radius: $border-radius;
}
.preview{
display: block;
padding:0; margin: 5em .5em .5em .5em;
&:empty{
text-align: center;
& ~ .cloud::after{
// content: none;
opacity:0;
visibility:hidden;
}
}
li {
counter-increment: file-count;
background-color: transparent;
padding-right: 2.75em;
&.uploaded {
counter-increment: none;
}
}
}
.cloud{
position:absolute;
margin:0; padding:0;
left:50%; top:.25em;
transform: scale(1) translateX(-50%);
height: 2em; width: 2em;
&::before{
content: url('data:image/svg+xml;charset=utf-8,%3Csvg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="#{url-color($upload-icon-color)}"%3E%3Cpath d="M51.7 26.7a20 20 0 0 0-19.7-16c-7.7 0-14.4 4.3-17.6 10.7A16 16 0 0 0 16 53.3h34.7C58.1 53.3 64 47.5 64 40c0-6.9-5.6-12.8-12.3-13.3zm-14.4 8v10.7H26.7V34.7h-8L32 21.3l13.3 13.3h-8z"/%3E%3C/svg%3E');
}
&::after{
top:-1.85em; left:-.45em;
content: counter(file-count);
display:block; position:relative;
width:1.5em; height:1.5em;
background-color: $warning-color;
opacity:1; visibility:visible;
border-radius:50%;
font-size: .6em; color: #FFF;
line-height:1.35; font-weight: 400;
text-align:center;
transition: all .5s ease-in-out;
animation: .5s bounce infinite;
}
}
}
// Photo booth
// Single image upload with camera capture
&.upload-photo{
overflow: hidden;
width:100%; max-width: 250px;
// Hover / drag state of dropzone
&:hover {
& label:after{
opacity: 1;
transform: translateY(0);
}
}
input[type="file"] {
&[accept*="capture"], &[capture]{
& ~ .camera {
display:block;
}
}
}
label{
z-index:$zindex-1;
position: absolute; display: block;
bottom: 0; margin:0; padding:0;
width: 100%; height:100%;
cursor: pointer;
pointer-events: all;
&:after {
position: absolute; display: block;
content: attr(data-label);
left: 0; bottom: 0!important; top: unset;
width: 100%; height: 3em;
padding: 0 1em;
background-color: $upload-dropzone-bgcolor;
color: #fff;
text-align:left;
line-height: 3em;
text-shadow: 0 1px 1px $upload-info-bgcolor;
opacity: 0;
transition: transform .25s ease, opacity .25s ease;
transform: translateY(100%);
}
}
.camera{
z-index: $zindex-1;
&::before{
content: url('data:image/svg+xml;charset=utf-8,%3Csvg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="#{url-color($upload-icon-color)}"%3E%3Cpath d="M50 40a15 15 0 1 0 0 30 15 15 0 0 0 0-30zm40-15H78a4.5 4.5 0 0 1-4-2.8l-3-9.4a4.5 4.5 0 0 0-4-2.8H33a4.5 4.5 0 0 0-4 2.8l-3 9.4a4.5 4.5 0 0 1-4 2.8H10A10 10 0 0 0 0 35v45a10 10 0 0 0 10 10h80a10 10 0 0 0 10-10V35a10 10 0 0 0-10-10zM50 80a25 25 0 1 1 0-50 25 25 0 0 1 0 50zm36.5-38a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z"/%3E%3C/svg%3E');
}
&.recording { // .recording class set by script
color: $error-color;
background-color: currentColor$error-color;
border-radius: 50%;
transform: scale(1);
animation: 1s recording infinite;
&::before{
content: '';
}
}
}
.preview {
padding:0;
text-align:center;
&.snapshot{
&::after{
z-index:1001;
content:''; display:inline-block; position:fixed;
background-color: #FFF;
left:0; top:0; bottom:0;
width:100%;
opacity: 1;
visibility: visible;
animation: 1s flash infinite;
}
}
&.portrait, &.landscape, &.square, &.circle {
overflow:hidden;
background-size: contain;
&::before {
content: '';
display: block;
padding-top:100%;
}
}
&.square, &.circle {
background-position: center center;
}
&.circle {
border-radius:50%;
background-size: cover;
}
li{
white-space: words;
position:absolute;
top:66%; left:50%;
padding-right: 2.75em;
max-width:70%;
transform:translate(-50%);
background-color: $upload-dropzone-bgcolor;
font-size:.8em;
text-shadow: 0 1px 1px $upload-info-bgcolor;
img{
width:0; height:0;
display:none;
}
}
video {
pointer-events: all;
position:absolute; display:block; top:0;
height: 100%; width:auto;
pointer-events: all;
transform:translateX(-12.5%);
transition: all .25s linear;
&:hover, &:focus, &:active {
cursor:pointer;
}
}
}
.error {
bottom: 50%; top: auto;
}
}
}
// Responsiveness
// First break point upwards
@media screen and (min-width: $responsive-breakpoint) {
.upload {
&.upload-multiple {
.preview {
li{
width:50%;
margin-right:0;
float:left;
b, strong, i {
font-size:.85em;
}
}
}
}
}
}
// Second break point upwards
@media screen and (min-width: $responsive-breakpoint-md) {
.upload {
&.upload-multiple {
.preview {
li{
width:25%;
float:left;
text-align:center;
padding-right:.5em;
img{
float:none;
width:100%; height:auto;
margin-bottom:$layout-spacing/2;
border-width:$layout-spacing;
}
i{
position:absolute;
top:$layout-spacing; right:$layout-spacing;
&::before {
background-color: $dark-color;
}
}
}
}
}
}
}
// Presentation layout CSS
// ------------------------------------------
html {
height:100%;
margin:0; padding:0;
// display:flex;
justify-content: center;
align-items: center;
}
body {
align-self: center;
background: $gray-color-dark;
background: linear-gradient(to right, $gray-color-dark, darken($gray-color-dark,23%));
margin:$layout-spacing; padding: 0;
font-family:'Raleway', 'Helvetica', 'Arial', Arial, Helvetica, sans;
color:$gray-color-light;
font-size: 16px;
}
main {}
a {
color: $gray-color-light;
text-decoration: none;
&:link{
color: $gray-color-light;
}
&:hover {
color: $gray-color;
}
&:focus, &:active {
color: $gray-color-dark;
}
}
h1, h2 {
font-weight:100; color:#FFF;
text-shadow: 1px 1px 0 rgba(0,0,0,.8);
display: block; width: 100%;
text-align:center;
}
h2 {
padding-bottom:0;
margin-bottom:0;
}
code {font-weight:600;}
p{
margin: 2*$layout-spacing;
padding:0;
text-align:center;
abbr{
cursor: help;
text-decoration:none;
text-decoration-line: dashed;
border-style: dotted;
border-width:0 0 1px 0;
}
}
section {
text-align:center;
margin: 0;
display: inline-block; width:100%;
}
form {
padding: 2em 1em;
border:0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment