Meme app
by PhilQ
HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css">
<div class="bg">
<form action="?" method="post" enctype="multipart/form-data">
<input type="file" id="picture" name="picture" accept="image/*" />
</form>
</div>
<!-- TODO: set to "?" -->
<a href="#" class="head">Meme generator</a>
<div id="loading">
<div class="lds-dual-ring"></div>
</div>
<div class="bottom">
<div class="modes show">
<a href="#" id="mode_image" class="on"><i class="fas fa-image"></i></a>
<a href="#" id="mode_adjust" class="disabled"><i class="fas fa-crop-alt"></i></a>
<a href="#" id="mode_text" class="disabled"><i class="fas fa-font"></i></a>
<a href="#" id="mode_emoji" class="disabled"><i class="fas fa-grin-alt"></i></a>
<a href="#" id="mode_draw" class="disabled"><i class="fas fa-signature"></i></a>
<a href="#" id="mode_done" class="disabled"><i class="fas fa-share-square_ fa-share_ fa-download_ fa-check-square_ fa-flag-checkered"></i></a>
</div>
<div class="confirm with-text">
<a href="#" id="confirm_cancel"><i class="fas fa-times"></i>Cancel</a>
<a href="#" id="confirm_ok"><i class="fas fa-check"></i>Ok</a>
</div>
</div>
<div class="sidebar">
<div class="image show">
<a href="#" id="upload_image"><i class="fas fa-camera"></i></a>
</div>
<div class="adjust">
</div>
<div class="text">
<a href="#" id="add_text"><i class="fas fa-plus"></i></a>
<a href="#" id="edit_text"><i class="fas fa-pen"></i></a>
<a href="#" id="delete_text"><i class="fas fa-times_ fa-trash-alt_ fa-trash"></i></a>
</div>
</div>
<div class="outerlist">
<div class="innerlist">
<div id="imagelist">
<a href="#" id="upload_button"><i class="fas fa-camera"></i></a>
</div>
</div>
</div>
<div class="uploadpreview">
<img id="previewimage" />
</div>
SCSS
*, *:before, *:after {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400;0,700;0,800;1,400&display=swap');
@mixin full {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
$background: #1a1d21;
$button: #1f2227;
$border: #2c2f34;
$txt-hover: #fbfbfb;
$txt-active: #c8c9cb;
$txt-normal: #616367;
$txt-inactive: #36393d;
html, body {
width: 100%;
height: 100%;
background: $background;
}
body {
font-family: 'Open Sans', sans-serif;
}
a {
text-decoration: none;
color: $txt-normal;
&.inactive {
color: $txt-inactive !important;
}
&.on {
color: $txt-active;
}
&:hover, &:focus {
color: $txt-hover;
}
}
.bg {
@include full;
z-index: -1;
background: $background;
opacity: 0;
overflow: hidden;
}
#loading {
@include full;
z-index: -1;
background: rgba($background, 0.8);
opacity: 0;
overflow: hidden;
&.show {
opacity: 1;
z-index: 110;
}
}
.lds-dual-ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: inline-block;
width: 64px;
height: 64px;
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 46px;
height: 46px;
margin: 1px;
border-radius: 50%;
border: 5px solid $txt-active;
border-color: $txt-active transparent $txt-active transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.head {
@include full;
z-index: 150;
bottom: auto;
height: 4rem;
background: $button;
box-shadow: 0px -10px 15px 10px rgba(0,0,0, 0.3);
}
.bottom {
@include full;
z-index: 100;
top: auto;
height: 4rem;
background: $button;
box-shadow: 0px 10px 15px 10px rgba(0,0,0, 0.3);
a {
position: relative;
flex-grow: 1;
flex-basis: 0;
height: 4rem;
box-sizing: content-box;
border-right: 1px solid transparent;
text-shadow: 0px 1px 2px rgba(0,0,0, 1);
font-size:...
JavaScript
function getOrientation(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var view = new DataView(e.target.result);
if (view.getUint16(0, false) != 0xFFD8)
{
return callback(-2);
}
var length = view.byteLength, offset = 2;
while (offset < length)
{
if (view.getUint16(offset+2, false) <= 8) return callback(-1);
var marker = view.getUint16(offset, false);
offset += 2;
if (marker == 0xFFE1)
{
if (view.getUint32(offset += 2, false) != 0x45786966)
{
return callback(-1);
}
var little = view.getUint16(offset += 6, false) == 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++)
{
if (view.getUint16(offset + (i * 12), little) == 0x0112)
{
return callback(view.getUint16(offset + (i * 12) + 8, little));
}
}
}
else if ((marker & 0xFF00) != 0xFF00)
{
break;
}
else
{
offset += view.getUint16(offset, false);
}
}
return callback(-1);
};
reader.readAsArrayBuffer(file);
}
function readFile(file) {
var reader = new FileReader();
reader.onloadend = function () {
getOrientation(file, function(orientation) {
processFile(reader.result, file.type, orientation);
});
}
reader.onerror = function () {
alert('There was an error reading the file!');
}
reader.readAsDataURL(file);
}
function processFile(dataURL, fileType, orientation) {
var maxWidth = 1024;
var maxHeight = 1024;
var image = new Image();
image.src = dataURL;
image.onload = function () {
var width = image.width;
var height = image.height;
var shouldResize = (width > maxWidth) || (height > maxHeight);
if (!shouldResize && 1 == orientation) {
previewFile(dataURL);
return;
}
var newWidth;
var newHeight;
if (shouldResize) {
if (width > height) {
newHeight = height * (maxWidth / width);
newWidth = maxWidth;
} else...