init
This commit is contained in:
commit
44c6129647
19
.editorconfig
Normal file
19
.editorconfig
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{*.html,*.css}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[{*.v,v.mod}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.js]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
**/*.v linguist-language=V
|
||||||
|
**/*.vv linguist-language=V
|
||||||
|
**/v.mod linguist-language=V
|
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
main
|
||||||
|
fu_local
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
Files/
|
||||||
|
|
||||||
|
# Assets
|
||||||
|
assets/bootstrap*
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.html
|
||||||
|
*.css
|
16
.prettierrc.json
Normal file
16
.prettierrc.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"useTabs": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"semi": true,
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "assets/*.js",
|
||||||
|
"options": {
|
||||||
|
"parser": "meriyah"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
57
assets/app.js
Normal file
57
assets/app.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
window.onload = function () {
|
||||||
|
// auto-submit by click file input
|
||||||
|
document.getElementById('upload_files').onchange = (e) => {
|
||||||
|
upload_files(e.target);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function upload_files(files_upload) {
|
||||||
|
let form_data = new FormData();
|
||||||
|
let upload_button = document.getElementById('upload_button');
|
||||||
|
|
||||||
|
update_upload_status(`Загружается ${files_upload.files.length} файл(а, ов)`);
|
||||||
|
for (var i = 0; i < files_upload.files.length; i++) {
|
||||||
|
form_data.append('files', files_upload.files[i]);
|
||||||
|
}
|
||||||
|
upload_button.classList.add('d-none');
|
||||||
|
files_upload.value = null;
|
||||||
|
|
||||||
|
let request = new XMLHttpRequest();
|
||||||
|
request.open('POST', '/upload');
|
||||||
|
|
||||||
|
request.upload.addEventListener('progress', function (e) {
|
||||||
|
let percent_completed = (e.loaded / e.total) * 100;
|
||||||
|
change_upload_state(Math.floor(percent_completed));
|
||||||
|
});
|
||||||
|
|
||||||
|
request.addEventListener('load', function (e) {
|
||||||
|
update_upload_status();
|
||||||
|
upload_button.classList.remove('d-none');
|
||||||
|
});
|
||||||
|
|
||||||
|
request.send(form_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function change_upload_state(percent_completed) {
|
||||||
|
let upload_state = document.getElementById('upload_state');
|
||||||
|
upload_state.classList.remove('d-none');
|
||||||
|
|
||||||
|
if (percent_completed == 100) {
|
||||||
|
upload_state.childNodes[1].style.width = '0%';
|
||||||
|
upload_state.setAttribute('aria-valuenow', 0);
|
||||||
|
upload_state.classList.add('d-none');
|
||||||
|
|
||||||
|
update_upload_status('Сохранение файлов...');
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
upload_state.childNodes[1].style.width = `${percent_completed}%`;
|
||||||
|
upload_state.setAttribute('aria-valuenow', percent_completed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_upload_status(message = '') {
|
||||||
|
let upload_status = document.getElementById('upload_status');
|
||||||
|
|
||||||
|
upload_status.innerText = message;
|
||||||
|
}
|
34
assets/styles.css
Normal file
34
assets/styles.css
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@import url('/bootstrap.min.css');
|
||||||
|
|
||||||
|
body {
|
||||||
|
text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5);
|
||||||
|
box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-container { max-width: 42em; }
|
||||||
|
|
||||||
|
.btn-light,
|
||||||
|
.btn-light:hover,
|
||||||
|
.btn-light:focus {
|
||||||
|
color: #333;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-masthead .nav-link {
|
||||||
|
color: rgba(255, 255, 255, .5);
|
||||||
|
border-bottom: .25rem solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-masthead .nav-link:hover,
|
||||||
|
.nav-masthead .nav-link:focus {
|
||||||
|
border-bottom-color: rgba(255, 255, 255, .25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-masthead .nav-link + .nav-link {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-masthead .active {
|
||||||
|
color: #fff;
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
43
src/index.html
Normal file
43
src/index.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="h-100" data-bs-theme="auto">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>♥️</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
||||||
|
<script type="text/javascript" src="app.js"></script>
|
||||||
|
<meta name="theme-color" content="#712cf9">
|
||||||
|
</head>
|
||||||
|
<body class="d-flex h-100 text-center text-bg-dark">
|
||||||
|
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
|
||||||
|
<header class="mb-auto">
|
||||||
|
<div>
|
||||||
|
<h3 class="float-md-start mb-0">Загрузчик файлов</h3>
|
||||||
|
<nav class="nav nav-masthead justify-content-center float-md-end">
|
||||||
|
<a class="nav-link fw-bold py-1 px-0 active" aria-current="page" href="#">Загрузка</a>
|
||||||
|
<a class="nav-link fw-bold py-1 px-0" href="#">Исходные коды</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="px-3">
|
||||||
|
<h1>Выберите файлы для загрузки</h1>
|
||||||
|
|
||||||
|
<input class="d-none" type="file" id="upload_files" multiple>
|
||||||
|
|
||||||
|
<button id="upload_button" class="btn btn-light" onclick="document.getElementById('upload_files').click();">Выбрать файлы</button>
|
||||||
|
|
||||||
|
<p id="upload_status" class="fw-bold"></p>
|
||||||
|
|
||||||
|
<div id="upload_state" class="d-none progress" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 75%"></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<footer class="mt-auto text-white-50">
|
||||||
|
<p>by Alexander Popov</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
52
src/main.v
Normal file
52
src/main.v
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import term
|
||||||
|
import vweb
|
||||||
|
|
||||||
|
const (
|
||||||
|
port = 8082
|
||||||
|
save_folder = 'Files'
|
||||||
|
)
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
vweb.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_app() &App {
|
||||||
|
mut app := &App{}
|
||||||
|
app.mount_static_folder_at(os.resource_abs_path('./assets'), '/')
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
term.clear()
|
||||||
|
|
||||||
|
os.ensure_folder_is_writable(os.resource_abs_path(save_folder)) or {
|
||||||
|
println('ОШИБКА: Отсутствует директория ${save_folder}')
|
||||||
|
exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
vweb.run_at(new_app(), vweb.RunParams{
|
||||||
|
port: port
|
||||||
|
}) or { panic(err) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut app App) index() vweb.Result {
|
||||||
|
return $vweb.html()
|
||||||
|
}
|
||||||
|
|
||||||
|
['/upload'; post]
|
||||||
|
pub fn (mut app App) upload() vweb.Result {
|
||||||
|
files_data := app.files['files']
|
||||||
|
|
||||||
|
for file in files_data {
|
||||||
|
filename := os.resource_abs_path(os.join_path('.', save_folder, '${time.now().unix}-${file.filename}'))
|
||||||
|
|
||||||
|
os.write_file(filename, file.data) or { panic(err) }
|
||||||
|
println('Файл ${file.filename} загружен')
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.text('Complete')
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user