diff options
Diffstat (limited to 'res')
| -rw-r--r-- | res/css/des.css | 1 | ||||
| -rw-r--r-- | res/css/setup.css | 49 | ||||
| -rw-r--r-- | res/langs/en.json | 6 | ||||
| -rw-r--r-- | res/langs/ru.json | 6 | ||||
| -rw-r--r-- | res/setup.html | 80 |
5 files changed, 139 insertions, 3 deletions
diff --git a/res/css/des.css b/res/css/des.css index 5d90b2c..fa9a50b 100644 --- a/res/css/des.css +++ b/res/css/des.css @@ -48,7 +48,6 @@ body.swap { grid-template-areas: "chat gutter video"; } - @media only screen and (orientation: portrait) { body { display: flex; diff --git a/res/css/setup.css b/res/css/setup.css new file mode 100644 index 0000000..9755ad3 --- /dev/null +++ b/res/css/setup.css @@ -0,0 +1,49 @@ +body { + display: flex; + height: 100vh; + align-items: center; + justify-content: center; +} + +.setup { + margin: auto; + padding: 2rem; + width: 320px; + display: flex; + flex-direction: column; + align-items: center; + + /* debug */ + background-color: #1a1a1f; + border-radius: 0.375rem; + + & h1 { + font-size: 1.75rem; + } +} + +.setup-form { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + + & button { + margin: 0; + padding: .75rem .5rem; + justify-content: center; + background-color: var(--accent); + color: #fff; + + &:hover { + filter: brightness(1.15); + } + } +} + +.form-errors { + display: flex; + flex-direction: column; + gap: 0.5rem; + color: var(--error); +} diff --git a/res/langs/en.json b/res/langs/en.json index b7f8246..1cda8aa 100644 --- a/res/langs/en.json +++ b/res/langs/en.json @@ -17,6 +17,8 @@ "openInApp": "Open in App", "hideThisMessage": "Hide this message", "usernameError": "Username length must be from 1 to $MAX characters and don't repeat another's. Characters &^<>'\" are not allowed.", + "passwordError": "Password length must be from $MIN to $MAX characters.", + "passwordsMismatchError": "Passwords do not match.", "passwordMatchError": "Wrong password.", "accessError": "Access error", "noPermission": "No '$PERMISSION' permission.", @@ -111,5 +113,7 @@ "off": "Off", "areYouSure": "Are you sure?", - "dataWillBeLost": "The data will be lost." + "dataWillBeLost": "The data will be lost.", + + "setupTitle": "Welcome to SyncTube!" } diff --git a/res/langs/ru.json b/res/langs/ru.json index b98237d..f9c5303 100644 --- a/res/langs/ru.json +++ b/res/langs/ru.json @@ -17,6 +17,8 @@ "openInApp": "Открыть в приложении", "hideThisMessage": "Скрыть это сообщение", "usernameError": "Ник должен быть от 1 до $MAX символов и не повторять чужие. Символы &^<>'\" запрещены.", + "passwordError": "Длина пароля должна быть от $MIN до $MAX символов.", + "passwordsMismatchError": "Пароли не совпадают.", "passwordMatchError": "Неправильный пароль.", "accessError": "Ошибка доступа", "noPermission": "Нет '$PERMISSION' разрешения.", @@ -111,5 +113,7 @@ "off": "Откл.", "areYouSure": "Вы уверены?", - "dataWillBeLost": "Данные будут потеряны." + "dataWillBeLost": "Данные будут потеряны.", + + "setupTitle": "Добро пожаловать в SyncTube!" } diff --git a/res/setup.html b/res/setup.html new file mode 100644 index 0000000..5d39518 --- /dev/null +++ b/res/setup.html @@ -0,0 +1,80 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> + <meta name="mobile-web-app-capable" content="yes"> + <meta name="apple-mobile-web-app-capable" content="yes"> + <link rel="manifest" href="manifest.json"> + <title>SyncTube</title> + <link rel="icon" href="img/favicon.svg" type="image/svg+xml"> + <link id="usertheme" href="css/des.css" rel="stylesheet"> + <link id="usertheme" href="css/setup.css" rel="stylesheet"> + <link id="customcss" href="css/custom.css" rel="stylesheet"> + +</head> + +<body> + <main class="setup"> + <h1 class="setup-title">SyncTube</h1> + <p>Create your admin account</p> + + <form id="setup-form" class="setup-form" action="/setup" method="POST"> + <input type="text" name="name" placeholder="Name"> + <input type="password" name="password" placeholder="Password"> + <input type="password" name="confirmation" placeholder="Repeat password"> + + <div id="form-errors" class="form-errors"></div> + + <button type="submit">Create</button> + </form> + </main> + + <script> + const formElement = document.getElementById("setup-form"); + const errorsElement = document.getElementById("form-errors"); + + formElement.addEventListener("submit", function (e) { + e.preventDefault(); + + const { name, password, confirmation } = formElement.elements; + const payload = { + name: name.value, + password: password.value, + passwordConfirmation: confirmation.value, + } + + fetch("/setup", { method: "POST", body: JSON.stringify(payload) }) + .then(res => res.json()) + .then(response => handleResponse(response)) + .catch(() => handleResponse(null)); + }, true); + + + function handleResponse(response) { + if (response.success) { + return window.location.reload(); + } + + const errors = !response + ? ["Unknown error"] + : (response.errors ?? []).map(item => item.error); + + showErrors(errorsElement, errors); + } + + function showErrors(container, errors) { + container.innerHTML = ""; + + errors.forEach((message) => { + const errorEl = document.createElement("div"); + errorEl.innerText = message; + container.appendChild(errorEl); + }); + } + </script> +</body> + +</html> |
