commit 44c61296477ebf182281912adf607fcb1bbb6e36 Author: Alexander Popov Date: Sun Jul 9 04:45:23 2023 +0300 init diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fab2f47 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3daa6c2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto eol=lf + +**/*.v linguist-language=V +**/*.vv linguist-language=V +**/v.mod linguist-language=V diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81f5bfc --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Binaries for programs and plugins +main +fu_local +*.exe +*.exe~ +*.so +*.dylib +*.dll + +# ... + +Files/ + +# Assets +assets/bootstrap* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..bbc3411 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +*.html +*.css diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..033553b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,16 @@ +{ + "printWidth": 100, + "endOfLine": "lf", + "useTabs": false, + "singleQuote": true, + "bracketSpacing": true, + "semi": true, + "overrides": [ + { + "files": "assets/*.js", + "options": { + "parser": "meriyah" + } + } + ] +} diff --git a/assets/app.js b/assets/app.js new file mode 100644 index 0000000..82cced1 --- /dev/null +++ b/assets/app.js @@ -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; +} diff --git a/assets/styles.css b/assets/styles.css new file mode 100644 index 0000000..8203ead --- /dev/null +++ b/assets/styles.css @@ -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; +} diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..c31b07e --- /dev/null +++ b/src/index.html @@ -0,0 +1,43 @@ + + + + + + ♥️ + + + + + +
+
+
+

Загрузчик файлов

+ +
+
+ +
+

Выберите файлы для загрузки

+ + + + + +

+ +
+
+
+
+ + + +
+ + diff --git a/src/main.v b/src/main.v new file mode 100644 index 0000000..8a0f5b3 --- /dev/null +++ b/src/main.v @@ -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') +} diff --git a/v.mod b/v.mod new file mode 100644 index 0000000..288d734 --- /dev/null +++ b/v.mod @@ -0,0 +1,7 @@ +Module { + name: 'fu_local' + description: '' + version: '0.0.1' + license: 'MIT' + dependencies: [] +}