323 lines
11 KiB
HTML
323 lines
11 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, minimum-scale=1.0, user-scalable=no">
|
|
<meta name="description" content="A fast and simple tool to convert to and from base64.">
|
|
<meta name="theme-color" content="#2196f3">
|
|
<link rel="manifest" href="manifest.json">
|
|
<link rel="icon" href="favicon.ico">
|
|
<meta http-equiv="cleartype" content="on">
|
|
<title>WebOasis - Base64 Converter</title>
|
|
<style>
|
|
html, body {
|
|
height: 100%;
|
|
margin: 0;
|
|
}
|
|
body {
|
|
background: #fafafa;
|
|
font-family: 'Roboto', 'Helvetica', 'Trebuchet MS1', sans-serif;
|
|
-webkit-font-smoothing: antialiased;
|
|
/* Disable rubber-band effect on scroll. */
|
|
-ms-touch-action: none;
|
|
|
|
display: -webkit-flex;
|
|
display: flex;
|
|
-webkit-flex-direction: column;
|
|
flex-direction: column;
|
|
}
|
|
.header {
|
|
background: #0078d4;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.26);
|
|
color: #fff;
|
|
font-size: 20px;
|
|
font-weight: 400;
|
|
padding: 0.65em;
|
|
|
|
-webkit-flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
}
|
|
.topRight {
|
|
color: rgba(250,250,250,0.8);
|
|
float: right;
|
|
font-size: 14px;
|
|
/* This aligns the link when directly next to the header. */
|
|
padding-top: 4px;
|
|
}
|
|
.topRight:hover, .topRight:focus {
|
|
color: rgb(250,250,250);
|
|
}
|
|
.io {
|
|
-webkit-flex: 1 1 auto;
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
display: -webkit-flex;
|
|
display: flex;
|
|
-webkit-flex-direction: row;
|
|
flex-direction: row;
|
|
}
|
|
.tile {
|
|
background: #fff;
|
|
border-radius: 2px;
|
|
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2);
|
|
margin: 2em;
|
|
/* When squished (mobile landscape), have a minimum standard of readability. */
|
|
min-height: 7em;
|
|
|
|
display: -webkit-flex;
|
|
display: flex;
|
|
-webkit-flex: 1 0 auto;
|
|
flex: 1 0 auto;
|
|
-webkit-flex-direction: column;
|
|
flex-direction: column;
|
|
width: 0;
|
|
}
|
|
/* Ensure there's not twice the padding when side-by-side. */
|
|
#leftTile { margin-right: 1em; }
|
|
#rightTile { margin-left: 1em; }
|
|
.type {
|
|
border-bottom: 1px solid #dbdbdb;
|
|
color: rgba(0,0,0,0.87);
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
padding: 0.65em;
|
|
|
|
-webkit-flex: 0 0 auto;
|
|
flex: 0 0 auto;
|
|
}
|
|
.content {
|
|
font-family: monospace;
|
|
font-size: 14px;
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
position: relative;
|
|
/* Margins must equal the total padding on children to ensure scrollbars stay flush. */
|
|
margin-bottom: 2em;
|
|
margin-right: 2em;
|
|
-webkit-flex: 1 1 auto;
|
|
flex: 1 1 auto;
|
|
}
|
|
.textarea {
|
|
border: none;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
height: 100%;
|
|
margin: 0;
|
|
/* Workaround to improve experience on browsers without new flexbox. */
|
|
min-height: 3em;
|
|
outline: none;
|
|
overflow: auto;
|
|
/* This padding must match the imagearea's padding. */
|
|
padding: 1em;
|
|
position: absolute;
|
|
resize: none;
|
|
width: 100%;
|
|
}
|
|
.textarea[readonly], .textarea[readonly='readonly'] {
|
|
background: #fff;
|
|
color: rgba(0,0,0,0.54);
|
|
}
|
|
.hidden {
|
|
display: none;
|
|
}
|
|
.errorSource {
|
|
background-color: #ffebee;
|
|
color: rgba(0,0,0,0.38);
|
|
}
|
|
.errorDestination {
|
|
color: rgba(0,0,0,0.38);
|
|
}
|
|
.imagearea {
|
|
background-position: center center;
|
|
background-repeat: no-repeat;
|
|
background-size: contain;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
height: 100%;
|
|
/* Workaround to improve experience on browsers without new flexbox. */
|
|
min-height: 3em;
|
|
margin: 0;
|
|
overflow: auto;
|
|
/* This padding must match the textarea's padding. */
|
|
padding: 1em;
|
|
position: absolute;
|
|
width: 100%;
|
|
}
|
|
/* Custom upload button to workaround multiple cross-browser issues. */
|
|
/* The basic approach is to hide an upload control on top of a button image. */
|
|
.customUpload {
|
|
bottom: 0;
|
|
height: 60px;
|
|
left: 0;
|
|
margin: auto;
|
|
overflow: hidden;
|
|
position: absolute;
|
|
right: 0;
|
|
top: 0;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
width: 60px;
|
|
}
|
|
/* When an image is present, move button to the top-left. */
|
|
.imagearea.containsImage .customUpload {
|
|
margin: 0;
|
|
position: relative;
|
|
}
|
|
.customUpload svg {
|
|
/* drop-shadow does not support the exact blur syntax so this has been approximated. */
|
|
-webkit-filter: drop-shadow(0 2px 1px rgba(0,0,0,0.14)) drop-shadow(0 1px 5px rgba(0,0,0,0.12)) drop-shadow(0 1px 1px rgba(0,0,0,0.1));
|
|
filter: drop-shadow(0 2px 1px rgba(0,0,0,0.14)) drop-shadow(0 1px 5px rgba(0,0,0,0.12)) drop-shadow(0 1px 1px rgba(0,0,0,0.1));
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
.customUpload svg path {
|
|
fill: #2196f3;
|
|
}
|
|
.customUpload:hover svg path {
|
|
fill: #1976d2;
|
|
}
|
|
.customUpload input {
|
|
cursor: pointer;
|
|
height: 200%;
|
|
left: 0;
|
|
opacity: 0;
|
|
position: absolute;
|
|
/* Disable blue glow on Chrome for Android due to cursor: pointer. */
|
|
-webkit-tap-highlight-color: transparent;
|
|
top: -100%;
|
|
width: 100%;
|
|
/* A filter on the svg will give it a stacking context, so ensure this stays on top. */
|
|
z-index: 99;
|
|
}
|
|
/* Drag and drop styles. */
|
|
#leftTile .dragover {
|
|
background-color: #e1f5fe;
|
|
}
|
|
/* On small screens, stack the areas without margin. */
|
|
@media (max-width: 1000px) {
|
|
.io {
|
|
-webkit-flex-direction: column;
|
|
flex-direction: column;
|
|
}
|
|
.tile {
|
|
border-radius: 0;
|
|
box-shadow: none;
|
|
margin: 0;
|
|
|
|
-webkit-flex: 1 0 auto;
|
|
flex: 1 0 auto;
|
|
height: 0;
|
|
width: 100%;
|
|
}
|
|
/* Remove side-by-side padding special-case. */
|
|
#leftTile { margin-right: 0; }
|
|
#rightTile { margin-left: 0; }
|
|
/* Workaround for crbug.com/586872 and Android 4.3 where the background is visible. */
|
|
body {
|
|
background: #fff;
|
|
}
|
|
}
|
|
/* Custom select box to workaround multiple cross-browser issues. */
|
|
/* The basic idea is to stack an invisible select above custom text and a dropdown icon. */
|
|
.customSelect {
|
|
border-bottom: 1px solid #dbdbdb;
|
|
display: inline-block;
|
|
margin: 0;
|
|
padding: 0;
|
|
position: relative;
|
|
-moz-user-select: none;
|
|
-ms-user-select: none;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
}
|
|
.customSelect svg {
|
|
display: inline-block;
|
|
height: 1em;
|
|
vertical-align: text-bottom;
|
|
width: 1em;
|
|
/* Hairline 2px adjustment just for aesthetics. */
|
|
margin-left: -2px;
|
|
}
|
|
.customSelect svg path {
|
|
fill: rgba(0,0,0,0.87);
|
|
}
|
|
.customSelect select {
|
|
-webkit-appearance: none;
|
|
-moz-appearance: none;
|
|
appearance: none;
|
|
border: none;
|
|
box-shadow: none;
|
|
font: inherit;
|
|
/* Position at +/- 10% to increase hit-testable area. */
|
|
height: 120%;
|
|
left: -10%;
|
|
margin: 0;
|
|
opacity: 0;
|
|
padding: 0;
|
|
position: absolute;
|
|
top: -10%;
|
|
width: 120%;
|
|
}
|
|
.customSelect select:focus {
|
|
outline: none;
|
|
}
|
|
/* Custom focus support because we cannot use parent CSS selectors. */
|
|
.customSelect#focused {
|
|
border-bottom: 1px solid rgba(0,0,0,0.87);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">WebOasis - Base64 Converter<a class="topRight" href="../">Go Back</a></div>
|
|
<div class="io">
|
|
<div id="leftTile" class="tile">
|
|
<div class="type">
|
|
<div class="customSelect">
|
|
<select id="leftTypeSelect">
|
|
<option value="text" selected="true">Text</option>
|
|
<option value="image">Image</option>
|
|
</select>
|
|
<span id="leftTypeText">Text</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-100 -100 300 300">
|
|
<path d="M0 0L100 0L50 80Z" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div id="leftContent" class="content">
|
|
<textarea id="leftTextarea" class="textarea" spellcheck="false">Hello world</textarea>
|
|
<div id="leftImageArea" class="imagearea hidden">
|
|
<div class="customUpload">
|
|
<input id="leftImageInput" type="file" accept="image/*" title="">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
<path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="rightTile" class="tile">
|
|
<div class="type">
|
|
<div class="customSelect">
|
|
<select id="rightTypeSelect">
|
|
<option value="base64utf8" selected="true">Base64 (utf8)</option>
|
|
<option value="base64ascii">Base64 (ascii)</option>
|
|
<option value="base64image" disabled="true">Base64 (image)</option>
|
|
</select>
|
|
<span id="rightTypeText">Base64</span>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-100 -100 300 300">
|
|
<path d="M0 0L100 0L50 80Z" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<div class="content">
|
|
<textarea id="rightTextarea" class="textarea" spellcheck="false">SGVsbG8gd29ybGQ=</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
<script src="base64.js" inline></script>
|
|
<script src="index.js" inline></script>
|
|
</html>
|