Rearranged files and beautified code

This commit is contained in:
Masahiko AMANO 2021-05-03 00:45:54 +03:00
parent a228f94dd0
commit 31d5b1c0f2
8 changed files with 341 additions and 310 deletions

View File

@ -2,15 +2,15 @@
## What's up? ## What's up?
Hey! This is a simple web-service called ![HuffPress](https://img.shields.io/badge/Huff-Press-orange.svg). What it does? Well, actually it *huffpresses* files... I mean, compresses files using the [Huffman compression](https://en.wikipedia.org/wiki/Huffman_coding "Read about it on Wikipedia"). Hey! This is a simple web-service called ![HuffPress](https://img.shields.io/badge/Huff-Press-orange.svg). What it does? Well, actually it _huffpresses_ files... I mean, compresses files using the [Huffman compression](https://en.wikipedia.org/wiki/Huffman_coding 'Read about it on Wikipedia').
## What do I need? ## What do I need?
- Any web browser - Any web browser
- ![PHP 7+](https://img.shields.io/badge/PHP-7+-blueviolet.svg) - ![PHP 7+](https://img.shields.io/badge/PHP-7+-blueviolet.svg)
- ![Python 3+](https://img.shields.io/badge/Python-3+-blue.svg) - ![Python 3.7+](https://img.shields.io/badge/Python-3+-blue.svg)
- `click` library - `click` library
## So, how do I use it? ## So, how do I use it?
I think it's too easy to explain the usage of this service, but anyway here's [a video guide](https://yadi.sk/i/aiy78bDaoKqoJQ "Watch!"). I think it's too easy to explain the usage of this service, but anyway here's [a video guide](https://yadi.sk/i/aiy78bDaoKqoJQ 'Watch!').

View File

@ -1,190 +1,189 @@
from os.path import dirname,basename,join,abspath as path from os.path import dirname, basename, join, abspath as path
from time import time from time import time
from datetime import datetime as dt from datetime import datetime as dt
import click import click
class Log: class Log:
def __init__(self,path,name): def __init__(self, path, name):
self.path=path self.path = path
self.name=name self.name = name
def log(self,msg,name=None): def log(self, msg, name=None):
if name is None: if name is None:
name=self.name name = self.name
now=dt.today() now = dt.today()
with open(self.path,'a',encoding='utf-8') as file: with open(self.path, 'a', encoding='utf-8') as file:
file.write(f'{now.year}-{str(now.month).rjust(2,"0")}-{str(now.day).rjust(2,"0")} ' file.write(f'{now.year}-{str(now.month).rjust(2, "0")}-{str(now.day).rjust(2, "0")} '
f'{str(now.hour).rjust(2,"0")}:{str(now.minute).rjust(2,"0")}:{str(now.second).rjust(2,"0")},{str(now.microsecond)[:3]}' f'{str(now.hour).rjust(2, "0")}:{str(now.minute).rjust(2, "0")}:{str(now.second).rjust(2, "0")},{str(now.microsecond)[:3]}'
' | ' ' | '
f'{name}' f'{name}'
' | ' ' | '
f'{msg}\n') f'{msg}\n')
log=Log(join(dirname(__file__),'hfm.log'),'hfm-py')
log = Log(join(dirname(__file__), 'hfm.log'), 'hfm-py')
def huffman(data): def huffman(data):
units={} #getting element-wise info units = {} # getting element-wise info
for c in data: for c in data:
if c in units: if c in units:
units[c]+=1 units[c] += 1
else: else:
units[c]=1 units[c] = 1
units,codes=sorted([([u],units[u]) for u in units],key=lambda u:u[1]),dict.fromkeys(units.keys(),'') units, codes = sorted([([u], units[u]) for u in units], key=lambda u: u[1]), dict.fromkeys(units.keys(), '')
while units: #creating Haffman table
if len(units)>2:
b=int(units[0][1]+units[1][1]>units[1][1]+units[2][1])
else:
b=0
for c in units[b][0]:
codes[c]='0'+codes[c]
for c in units[1+b][0]:
codes[c]='1'+codes[c]
units[2*b]=units[b][0]+units[1+b][0],units[b][1]+units[1+b][1]
if len(units)>2:
del units[1]
units.sort(key=lambda u:u[1])
else:
del units
break
return codes
while units: # creating Haffman table
if len(units) > 2:
b = int(units[0][1] + units[1][1] > units[1][1] + units[2][1])
else:
b = 0
for c in units[b][0]:
codes[c] = '0' + codes[c]
for c in units[1 + b][0]:
codes[c] = '1' + codes[c]
units[2 * b] = units[b][0] + units[1 + b][0], units[b][1] + units[1 + b][1]
if len(units) > 2:
del units[1]
units.sort(key=lambda u: u[1])
else:
del units
break
return codes
def tbl(table): def tbl(table):
table=';'.join([f'{k};{table[k]}' for k in table]).split(';') table = ';'.join([f'{k};{table[k]}' for k in table]).split(';')
byts=[] byts = []
for i in range(len(table)): for i in range(len(table)):
if i%2: if i % 2:
num=table[i] num = table[i]
else: else:
num=bin(int(table[i]))[2:] num = bin(int(table[i]))[2:]
while len(num)>7: while len(num) > 7:
byts.append(int('1'+num[:7],2)) byts.append(int('1' + num[:7], 2))
num=num[7:] num = num[7:]
byts.append(int(num,2)) byts.append(int(num, 2))
byts.append(8-len(num)) byts.append(8 - len(num))
return byts return byts
def detbl(byts): def detbl(byts):
dec=[] dec = []
table={} table = {}
stack='' stack = ''
i=0 i = 0
while i<len(byts): while i < len(byts):
if byts[i][0]=='1': if byts[i][0] == '1':
stack+=byts[i][1:] stack += byts[i][1:]
else: else:
stack+=byts[i][int(byts[i+1],2):] stack += byts[i][int(byts[i + 1], 2):]
dec.append(stack[:]) dec.append(stack[:])
stack='' stack = ''
i+=1 i += 1
i+=1 i += 1
for i in range(0,len(dec),2): for i in range(0, len(dec), 2):
table[dec[i+1]]=int(dec[i],2) table[dec[i + 1]] = int(dec[i], 2)
return table return table
def compress_file(filename): def compress_file(filename):
log.log(f"Loading '{filename}'...") log.log(f"Loading '{filename}'...")
with open(filename,'rb') as file: #get data with open(filename, 'rb') as file: # get data
data=list(map(int,file.read())) data = list(map(int, file.read()))
log.log(f'Original size: {len(data)} bytes.') log.log(f'Original size: {len(data)} bytes.')
log.log('Creating Huffman table...') log.log('Creating Huffman table...')
hf=huffman(data) hf = huffman(data)
table=tbl(hf) table = tbl(hf)
log.log('Embedding Huffman table...') log.log('Embedding Huffman table...')
out=[] out = []
ln=bin(len(table))[2:] #embed the table ln = bin(len(table))[2:] # embed the table
while len(ln)>7: while len(ln) > 7:
out.append(int('1'+ln[:7],2)) out.append(int('1' + ln[:7], 2))
ln=ln[7:] ln = ln[7:]
out+=[int(ln,2),8-len(ln)]+table out += [int(ln, 2), 8 - len(ln)] + table
log.log(f'Huffman table size: {len(out)} bytes.') log.log(f'Huffman table size: {len(out)} bytes.')
log.log('Compressing...') log.log('Compressing...')
stack='' stack = ''
for i in range(len(data)): #encode to Haffman for i in range(len(data)): # encode to Haffman
stack+=hf[data[i]] stack += hf[data[i]]
while len(stack)>=8: while len(stack) >= 8:
out.append(int(stack[:8],2)) out.append(int(stack[:8], 2))
stack=stack[8:] stack = stack[8:]
out+=[int(stack.ljust(8,'0'),2),len(stack)] out += [int(stack.ljust(8, '0'), 2), len(stack)]
log.log(f'Compressed size: {len(out)} bytes.') log.log(f'Compressed size: {len(out)} bytes.')
log.log(f"Saving to '{filename}.hfm'...") log.log(f"Saving to '{filename}.hfm'...")
with open(f'{filename}.hfm','wb') as file: #save Haffman code with open(f'{filename}.hfm', 'wb') as file: # save Haffman code
file.write(bytes(out)) file.write(bytes(out))
log.log('SUCCESSFULLY COMPRESSED') log.log('SUCCESSFULLY COMPRESSED')
print(f'"origSize":{len(data)},') print(f'"origSize":{len(data)},')
print(f'"compSize":{len(out)},') print(f'"compSize":{len(out)},')
def decompress_file(filename): def decompress_file(filename):
log.log(f"Loading '{filename}'...") log.log(f"Loading '{filename}'...")
with open(filename,'rb') as file: #get data with open(filename, 'rb') as file: # get data
data=[bin(byte)[2:].rjust(8,'0')for byte in file.read()] data = [bin(byte)[2:].rjust(8, '0') for byte in file.read()]
os=len(data) os = len(data)
data[-2]=data[-2][:int(data[-1],2)] data[-2] = data[-2][:int(data[-1], 2)]
del data[-1] del data[-1]
log.log('Extracting Huffman table...') log.log('Extracting Huffman table...')
ln='' #extract the table ln = '' # extract the table
i=0 i = 0
while 1: while 1:
if data[i][0]=='1': if data[i][0] == '1':
ln+=data[i][1:] ln += data[i][1:]
else: else:
ln+=data[i][int(data[i+1],2):] ln += data[i][int(data[i + 1], 2):]
break break
i+=1 i += 1
del data[:i+2] del data[:i + 2]
table=detbl(data[:int(ln,2)]) table = detbl(data[:int(ln, 2)])
del data[:int(ln,2)] del data[:int(ln, 2)]
data=''.join(data) data = ''.join(data)
stack='' stack = ''
out=[] out = []
log.log('Decompressing...') log.log('Decompressing...')
for c in data: #decode Haffman for c in data: # decode Haffman
stack+=c stack += c
if stack in table: if stack in table:
out.append(int(table[stack])) out.append(int(table[stack]))
stack='' stack = ''
filename=filename[:-4] filename = filename[:-4]
log.log(f"Saving to '{filename}'...") log.log(f"Saving to '{filename}'...")
with open(f'{filename}','wb') as file: #save decoded data with open(f'{filename}', 'wb') as file: # save decoded data
file.write(bytes(out)) file.write(bytes(out))
log.log(f'SUCCESSFULLY DECOMPRESSED') log.log(f'SUCCESSFULLY DECOMPRESSED')
print(f'"compSize":{os},') print(f'"compSize":{os},')
print(f'"origSize":{len(out)},') print(f'"origSize":{len(out)},')
@click.command(options_metavar='[-c / -d]') @click.command(options_metavar='[-c / -d]')
@click.argument('files',nargs=-1,metavar='<file [file [...]]>') @click.argument('files', nargs=-1, metavar='<file [file [...]]>')
@click.option('-c/-d','comp',default=True,help='Compress/decompress mode selectors.') @click.option('-c/-d', 'comp', default=True, help='Compress/decompress mode selectors.')
def CLI(files,comp): def CLI(files, comp):
log.log(f'hfm {"-c"*comp}{"-d"*(not comp)} {" ".join(files)}') log.log(f'hfm {"-c" * comp}{"-d" * (not comp)} {" ".join(files)}')
for file in files: for file in files:
print('{') print('{')
stime=time() stime = time()
if comp: if comp:
compress_file(path(file)) compress_file(path(file))
wtime=time()-stime wtime = time() - stime
print('"status":true,') print('"status":true,')
print(f'"time":{round(wtime,3)},') print(f'"time":{round(wtime, 3)},')
print(f'"dlink":"./files/{basename(file)+".hfm"}"') print(f'"dlink":"./files/{basename(file) + ".hfm"}"')
else: else:
try: try:
decompress_file(path(file)) decompress_file(path(file))
wtime=time()-stime wtime = time() - stime
print('"status":true,') print('"status":true,')
print(f'"time":{round(wtime,3)},') print(f'"time":{round(wtime, 3)},')
print(f'"dlink":"./files/{basename(file)[:-4]}"') print(f'"dlink":"./files/{basename(file)[:-4]}"')
except Exception as e: except Exception as e:
print(f'"status":false') print(f'"status":false')
print('}') print('}')
if __name__=='__main__': if __name__ == '__main__':
CLI() CLI()

View File

@ -1,12 +1,12 @@
<?php <?php
$mode=$_POST['mode']; $mode = $_POST['mode'];
$file=$_FILES['file']; $file = $_FILES['file'];
if (!is_dir(dirname(__file__).'/files')){ if (!is_dir(dirname(__file__) . '/files')) {
mkdir(dirname(__file__).'/files'); mkdir(dirname(__file__) . '/files');
} }
$path=dirname(__file__).'/files/'.basename($file['name']); $path = dirname(__file__) . '/files/' . basename($file['name']);
move_uploaded_file($file['tmp_name'],$path); move_uploaded_file($file['tmp_name'], $path);
$result=json_decode((string)shell_exec('python '.dirname(__file__).'/huffman.py -'.($mode=='compress'?'c':'d').' "'.$path.'"')); $result = json_decode((string)shell_exec('python ' . dirname(__file__) . '/huffman.py -' . ($mode == 'compress' ? 'c' : 'd') . ' "' . $path . '"'));
header('Content-Type: application/json'); header('Content-Type: application/json');
echo json_encode($result); echo json_encode($result);
?> ?>

View File

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 190 KiB

View File

Before

Width:  |  Height:  |  Size: 972 KiB

After

Width:  |  Height:  |  Size: 972 KiB

View File

@ -1,59 +1,76 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HuffPress</title> <title>HuffPress</title>
<link rel="shortcut icon" href="favicon.ico"> <link rel="shortcut icon" href="./favicon.ico" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <link
<link rel="stylesheet" href="style.css"> rel="stylesheet"
<script src="http://code.jquery.com/jquery-latest.min.js"></script> href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
</head> integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
<body> crossorigin="anonymous"
<header> />
<h1>HuffPress</h1> <link rel="stylesheet" href="./style.css" />
</header> <script src="http://code.jquery.com/jquery-latest.min.js"></script>
<main> </head>
<h2>Compress your files with the Huffman compression!</h2> <body>
<form id="form" class="was-validated" method="post" enctype="multipart/form-data"> <header>
<div class="form-group"> <h1>HuffPress</h1>
<label for="mode">Select mode</label> </header>
<select id="mode" class="form-control" id="mode"> <main>
<option value="compress">Compress</option> <h2>Compress your files with the Huffman compression!</h2>
<option value="decompress">Decompress</option> <form
</select> id="form"
class="was-validated"
method="post"
enctype="multipart/form-data"
>
<div class="form-group">
<label for="mode">Select mode</label>
<select id="mode" class="form-control" id="mode">
<option value="compress">Compress</option>
<option value="decompress">Decompress</option>
</select>
</div>
<div class="form-group">
<div class="custom-file">
<label class="custom-file-label" for="file">Choose file...</label>
<input id="file" type="file" class="custom-file-input" required />
<div class="invalid-feedback">Let's choose your file!</div>
<div class="valid-feedback">Ready to start!</div>
</div>
</div>
<div class="form-group">
<input
id="submit"
type="submit"
class="btn btn-primary"
value="HuffPress!"
/>
</div>
</form>
</main>
<div class="wrap">
<div class="process">
<img src="./images/processing.gif" alt="Processing..." />
</div> </div>
<div class="form-group"> <div class="complete">
<div class="custom-file"> <h3>Completed!</h3>
<label class="custom-file-label" for="file">Choose file...</label> <p class="status"></p>
<input id="file" type="file" class="custom-file-input" required> <div class="btncont">
<div class="invalid-feedback">Let's choose your file!</div> <a id="dlink" class="btn btn-primary" href="" download>Download</a>
<div class="valid-feedback">Ready to start!</div> <button class="btn closebtn">Close</button>
</div> </div>
</div> </div>
<div class="form-group"> <div class="error">
<input id="submit" type="submit" class="btn btn-primary" value="HuffPress!"> <h3>Error!</h3>
</div> <p class="status">Unable to decompress this file!</p>
</form> <div class="btncont">
</main> <button class="btn closebtn">Close</button>
<div class="wrap"> </div>
<div class="process"><img src="processing.gif" alt="Processing..."></div>
<div class="complete">
<h3>Completed!</h3>
<p class="status"></p>
<div class="btncont">
<a id="dlink" class="btn btn-primary" href="" download>Download</a>
<button class="btn closebtn">Close</button>
</div> </div>
</div> </div>
<div class="error"> <script src="./script.js"></script>
<h3>Error!</h3> </body>
<p class="status">Unable to decompress this file!</p>
<div class="btncont">
<button class="btn closebtn">Close</button>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html> </html>

134
script.js
View File

@ -1,76 +1,88 @@
function winsize(){ function winsize() {
if (!toggled && $(window).width()/$(window).height()>(90/31) || if (
toggled && $(window).width()/($(window).height()-219)>(18/7)){ (!toggled && $(window).width() / $(window).height() > 90 / 31) ||
$('body').css('justify-content','flex-start'); (toggled && $(window).width() / ($(window).height() - 219) > 18 / 7)
) {
$('body').css('justify-content', 'flex-start')
} else { } else {
$('body').css('justify-content','center'); $('body').css('justify-content', 'center')
} }
}; }
window.onload=function(){ window.onload = function () {
setTimeout(()=>{$('main').slideDown(500)},100); setTimeout(() => {
winsize(); $('main').slideDown(500)
}; }, 100)
$(window).on('resize',function(){ winsize()
winsize(); }
}); $(window).on('resize', function () {
winsize()
})
var toggled=false; var toggled = false
$('h2').click(function(){ $('h2').click(function () {
var time=300; var time = 300
if (toggled) { if (toggled) {
$('form').slideUp(time); $('form').slideUp(time)
$('main').css('min-height','9vw'); $('main').css('min-height', '9vw')
setTimeout(()=>{$('h2').css('border-bottom','0')},time); setTimeout(() => {
toggled=false; $('h2').css('border-bottom', '0')
winsize(); }, time)
toggled = false
winsize()
} else { } else {
$('main').css('min-height','calc(9vw + 260px)'); $('main').css('min-height', 'calc(9vw + 260px)')
$('form').slideDown(time); $('form').slideDown(time)
$('form').css('display','flex'); $('form').css('display', 'flex')
$('h2').css('border-bottom','1px solid black'); $('h2').css('border-bottom', '1px solid black')
toggled=true; toggled = true
setTimeout(()=>{winsize()},time); setTimeout(() => {
winsize()
}, time)
} }
}); })
$('form').on('submit',function submit(e){ $('form').on('submit', function submit(e) {
e.preventDefault(); e.preventDefault()
$('.wrap').css('display','flex'); $('.wrap').css('display', 'flex')
$('.process').css('display','block'); $('.process').css('display', 'block')
var form=new FormData(); var form = new FormData()
form.append('mode',$('#mode').val()); form.append('mode', $('#mode').val())
$.each($('#file')[0].files, function(i, file) { $.each($('#file')[0].files, function (i, file) {
form.append('file', file); form.append('file', file)
}); })
$.ajax({ $.ajax({
url: 'huffpress.php', url: 'huffpress.php',
type: 'POST', type: 'POST',
processData: false, processData: false,
contentType: false, contentType: false,
dataType: 'json', dataType: 'json',
data: form, data: form,
success: function(resp){ success: function (resp) {
console.log(resp); console.log(resp)
if (resp.status){ if (resp.status) {
$('.process').css('display','none'); $('.process').css('display', 'none')
$('.complete').css('display','block'); $('.complete').css('display', 'block')
if ($('#mode').val()=='compress'){ if ($('#mode').val() == 'compress') {
$('.complete .status').html(`Original size:&nbsp;&nbsp;&nbsp;${resp.origSize} B<br>Compressed size: ${resp.compSize} B<br>Time:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${resp.time} s`); $('.complete .status').html(
`Original size:&nbsp;&nbsp;&nbsp;${resp.origSize} B<br>Compressed size: ${resp.compSize} B<br>Time:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${resp.time} s`
)
} else { } else {
$('.complete .status').html(`Compressed size: ${resp.compSize} B<br>Original size:&nbsp;&nbsp;&nbsp;${resp.origSize} B<br>Time:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${resp.time} s`); $('.complete .status').html(
`Compressed size: ${resp.compSize} B<br>Original size:&nbsp;&nbsp;&nbsp;${resp.origSize} B<br>Time:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${resp.time} s`
)
} }
$('#dlink').attr('href',resp.dlink); $('#dlink').attr('href', resp.dlink)
} else { } else {
$('.process').css('display','none'); $('.process').css('display', 'none')
$('.error').css('display','block'); $('.error').css('display', 'block')
} }
} },
}); })
}); })
$('.closebtn').click(function(){ $('.closebtn').click(function () {
$('.wrap').css('display','none'); $('.wrap').css('display', 'none')
$('.process').css('display','none'); $('.process').css('display', 'none')
$('.error').css('display','none'); $('.error').css('display', 'none')
$('.complete').css('display','none'); $('.complete').css('display', 'none')
}); })

View File

@ -1,11 +1,12 @@
@import url('https://fonts.googleapis.com/css2?family=Epilogue&family=Secular+One&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Epilogue&family=Secular+One&display=swap');
html,body{ html,
body {
width: 100%; width: 100%;
min-height: 100vh; min-height: 100vh;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
body{ body {
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
@ -15,16 +16,16 @@ body{
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-image: url(bg.webp); background-image: url(./images/bg.webp);
background-size: cover; background-size: cover;
} }
header{ header {
margin: 0; margin: 0;
margin-top: 2vw; margin-top: 2vw;
padding: 0; padding: 0;
text-align: center; text-align: center;
} }
h1{ h1 {
margin: 0; margin: 0;
padding: 0; padding: 0;
color: white; color: white;
@ -33,21 +34,21 @@ h1{
text-shadow: 0 0 1vw black; text-shadow: 0 0 1vw black;
cursor: default; cursor: default;
} }
main{ main {
display: none; display: none;
margin-bottom: 2vw; margin-bottom: 2vw;
background-color: #fff8; background-color: #fff8;
box-shadow: 0 0 .5vw black; box-shadow: 0 0 0.5vw black;
border-radius: 1.5vw; border-radius: 1.5vw;
min-height: 9vw; min-height: 9vw;
transition: .3s; transition: 0.3s;
overflow: hidden; overflow: hidden;
} }
main:hover{ main:hover {
background-color: #fff; background-color: #fff;
box-shadow: 0 0 1vw black; box-shadow: 0 0 1vw black;
} }
h2{ h2 {
margin: 0; margin: 0;
padding: 0 2vw; padding: 0 2vw;
height: 9vw; height: 9vw;
@ -55,14 +56,14 @@ h2{
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: hsla(270,80%,80%,.6); background-color: hsla(270, 80%, 80%, 0.6);
border-bottom: 0; border-bottom: 0;
font-family: Secular One; font-family: Secular One;
font-size: 3vw; font-size: 3vw;
text-shadow: 2.5px 2px .5px white; text-shadow: 2.5px 2px 0.5px white;
cursor: pointer; cursor: pointer;
} }
form{ form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -71,7 +72,7 @@ form{
padding: 2vw 2vw; padding: 2vw 2vw;
box-sizing: border-box; box-sizing: border-box;
} }
.wrap{ .wrap {
display: none; display: none;
position: absolute; position: absolute;
left: 0; left: 0;
@ -83,7 +84,9 @@ form{
align-items: center; align-items: center;
z-index: 10; z-index: 10;
} }
.process,.complete,.error{ .process,
.complete,
.error {
display: none; display: none;
padding: 2vw 5vw; padding: 2vw 5vw;
background-color: white; background-color: white;
@ -92,28 +95,28 @@ form{
font-size: 5vw; font-size: 5vw;
cursor: default; cursor: default;
} }
.process img{ .process img {
width: 15vw; width: 15vw;
} }
h3{ h3 {
margin: 0; margin: 0;
margin-top: .5vw; margin-top: 0.5vw;
font-family: Secular One; font-family: Secular One;
font-size: 3vw; font-size: 3vw;
} }
.status{ .status {
margin: 0; margin: 0;
margin-top: .5vw; margin-top: 0.5vw;
font-family: monospace; font-family: monospace;
font-size: 1.5vw; font-size: 1.5vw;
} }
.btncont{ .btncont {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.btncont *{ .btncont * {
font-size: 2vw; font-size: 2vw;
} }
#dlink{ #dlink {
margin-right: 1vw; margin-right: 1vw;
} }