start_point
|
@ -0,0 +1 @@
|
|||
/target
|
|
@ -0,0 +1,5 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/lavina_bridge.iml" filepath="$PROJECT_DIR$/.idea/lavina_bridge.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "lavina_bridge"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
http = "1.1.0"
|
||||
warp = "0.3"
|
||||
reqwest= { version = "0.12.5", features = ["json"] }
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9.1"
|
||||
|
||||
log = "0.4.22"
|
||||
env_logger = "0.11.5"
|
||||
|
||||
config = "0.14.0"
|
|
@ -0,0 +1,8 @@
|
|||
local_server_address = "127.0.0.1"
|
||||
|
||||
#bridge_host = "127.0.0.1"
|
||||
bridge_port = "3030"
|
||||
|
||||
#lavina_host = "127.0.0.1"
|
||||
lavina_http_port = 8080
|
||||
lavina_irc_port = 6667
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 210 KiB |
|
@ -0,0 +1,23 @@
|
|||
use serde::Deserialize;
|
||||
use config::{Config, File};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub local_server_address: String,
|
||||
pub bridge_port: u16,
|
||||
pub lavina_http_port: u16,
|
||||
pub lavina_irc_port: u16,
|
||||
}
|
||||
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
pub fn load_config() -> AppConfig {
|
||||
let settings = Config::builder()
|
||||
.add_source(File::with_name("config.toml"))
|
||||
.build().unwrap();
|
||||
|
||||
settings
|
||||
.try_deserialize()
|
||||
.unwrap()
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
pub mod service;
|
||||
|
||||
|
||||
pub use crate::models::models::User;
|
|
@ -0,0 +1,57 @@
|
|||
use std::sync::Arc;
|
||||
use crate::lavina_clients::http_client::LavinaHttpClient;
|
||||
pub use crate::models::models::User;
|
||||
use serde_json::json;
|
||||
use warp::Filter;
|
||||
use crate::lavina_clients::errors::*;
|
||||
|
||||
pub struct CreateUserService {
|
||||
lavina_client: LavinaHttpClient,
|
||||
}
|
||||
|
||||
impl CreateUserService {
|
||||
pub fn new(laina_http_client: LavinaHttpClient) -> Self {
|
||||
CreateUserService { lavina_client: laina_http_client }
|
||||
}
|
||||
|
||||
pub async fn create_user(&self, user: User) -> Result<impl warp::Reply, warp::Rejection> {
|
||||
match self.lavina_client.new_player(&user.login, &user.password).await {
|
||||
Ok(()) => {
|
||||
let response = json!({"create_result": "User created"});
|
||||
Ok::<_, warp::Rejection>(warp::reply::json(&response))
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Error creating user: {:?}", err);
|
||||
let error_response = match err {
|
||||
PlayerError::UserAlreadyExists(ref name) => {
|
||||
json!({"error": format!("User '{}' already exists", name)})
|
||||
}
|
||||
PlayerError::RequestError(_) => {
|
||||
json!({"error": "Error during request to lavina"})
|
||||
}
|
||||
PlayerError::Other(ref msg) => {
|
||||
json!({"error": format!("Unknown error: {}", msg)})
|
||||
}
|
||||
};
|
||||
Ok::<_, warp::Rejection>(warp::reply::json(&error_response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn create_user_route(self: Arc<Self>) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
|
||||
warp::path("create-user")
|
||||
.and(warp::post())
|
||||
.and(warp::body::json())
|
||||
.and_then({
|
||||
let user_manager = Arc::clone(&self); // Клонируем Arc для использования в асинхронном блоке
|
||||
move |user: User| {
|
||||
let user_manager = Arc::clone(&user_manager);
|
||||
async move {
|
||||
user_manager.create_user(user).await
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
use reqwest::Error as ReqwestError;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PlayerError {
|
||||
UserAlreadyExists(String),
|
||||
RequestError(ReqwestError),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for PlayerError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PlayerError::UserAlreadyExists(name) => write!(f, "Пользователь с именем '{}' уже существует", name),
|
||||
PlayerError::RequestError(err) => write!(f, "Ошибка запроса: {}", err),
|
||||
PlayerError::Other(msg) => write!(f, "Ошибка: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ReqwestError> for PlayerError {
|
||||
fn from(err: ReqwestError) -> PlayerError {
|
||||
PlayerError::RequestError(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
use crate::lavina_clients::errors::*;
|
||||
use reqwest::Client;
|
||||
use crate::configuration::AppConfig;
|
||||
|
||||
pub struct LavinaHttpClient {
|
||||
client: Client,
|
||||
create_player_url: String,
|
||||
set_password_url: String,
|
||||
}
|
||||
|
||||
impl LavinaHttpClient {
|
||||
pub fn new(config: &AppConfig) -> Self {
|
||||
LavinaHttpClient {
|
||||
client: Client::new(),
|
||||
|
||||
create_player_url: format!(
|
||||
"http://{}:{}/mgmt/create_player",
|
||||
config.local_server_address, config.lavina_http_port
|
||||
),
|
||||
set_password_url: format!(
|
||||
"http://{}:{}/mgmt/set_password",
|
||||
config.local_server_address, config.lavina_http_port
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn new_player(&self, name: &str, password: &str) -> Result<(), PlayerError> {
|
||||
let mut create_query = std::collections::HashMap::new();
|
||||
create_query.insert("name", name);
|
||||
|
||||
let create_user_response = self.client.post(&self.create_player_url)
|
||||
.json(&create_query).send().await.map_err(PlayerError::from)?;
|
||||
|
||||
let response_message = create_user_response.text().await.map_err(PlayerError::from)?;
|
||||
|
||||
if response_message.contains("error returned from database: (code: 2067) UNIQUE constraint failed: users.name") {
|
||||
log::info!("User {:?} already exists. Response from server: {:?}", name, response_message);
|
||||
return Err(PlayerError::UserAlreadyExists(name.to_string()));
|
||||
} else {
|
||||
log::info!("Created user. Response: {:?}", response_message);
|
||||
self.set_password(name, password).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_password(&self, name: &str, password: &str) -> Result<(), PlayerError> {
|
||||
let mut set_pass_query = std::collections::HashMap::new();
|
||||
set_pass_query.insert("player_name", name);
|
||||
set_pass_query.insert("password", password);
|
||||
|
||||
let set_password_response = self.client.post(&self.set_password_url)
|
||||
.json(&set_pass_query).send().await.map_err(PlayerError::from)?;
|
||||
|
||||
let _ = set_password_response.text().await.map_err(PlayerError::from)?;
|
||||
log::info!("Password set for user: {:?}", name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod http_client;
|
||||
pub mod errors;
|
|
@ -0,0 +1,65 @@
|
|||
mod lavina_clients;
|
||||
mod create_user;
|
||||
mod models;
|
||||
mod configuration;
|
||||
|
||||
use warp::Filter;
|
||||
use std::sync::Arc;
|
||||
use log::Level;
|
||||
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
env_logger::Builder::from_default_env()
|
||||
.filter_level(Level::Info.to_level_filter())
|
||||
.init();
|
||||
|
||||
|
||||
|
||||
|
||||
let config = configuration::load_config();
|
||||
|
||||
println!("Local Server Address: {}", config.local_server_address);
|
||||
println!("Server Host: {}", config.bridge_port);
|
||||
println!("Lavina HTTP Address: {}", config.lavina_http_port);
|
||||
println!("Lavina IRC Address: {}", config.lavina_irc_port);
|
||||
|
||||
|
||||
let lavina_http_client = lavina_clients::http_client::LavinaHttpClient::new(&config);
|
||||
let create_user_service = create_user::service::CreateUserService::new(lavina_http_client);
|
||||
|
||||
let hello = warp::path::end()
|
||||
.map(|| warp::reply::html("Hello, World!"));
|
||||
|
||||
let images_dir = std::env::current_dir()
|
||||
.expect("Не удалось получить текущую директорию")
|
||||
.join("images");
|
||||
|
||||
let images = warp::path("images")
|
||||
.and(warp::fs::dir(images_dir));
|
||||
|
||||
let webpages_files = std::env::current_dir()
|
||||
.expect("Не удалось получить текущую директорию")
|
||||
.join("webpages");
|
||||
|
||||
let webpages_routes = warp::path("webpages")
|
||||
.and(warp::fs::dir(webpages_files));
|
||||
|
||||
let create_user_route = Arc::new(create_user_service).create_user_route();
|
||||
|
||||
let routes = hello
|
||||
.or(images)
|
||||
.or(webpages_routes)
|
||||
.or(create_user_route);
|
||||
|
||||
let ip_addr: IpAddr = config.local_server_address.parse().expect("REASON");
|
||||
let socket_addr = SocketAddr::new(ip_addr, config.bridge_port);
|
||||
|
||||
warp::serve(routes)
|
||||
.run(socket_addr)
|
||||
.await;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod models;
|
|
@ -0,0 +1,9 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct User {
|
||||
pub login: String,
|
||||
pub password: String,
|
||||
}
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 210 KiB |
|
@ -0,0 +1,73 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<title>My Website Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="welcome-to">
|
||||
<h1>Welcome to</h1>
|
||||
</div>
|
||||
|
||||
<div class="shimmering-name">
|
||||
<h1>Lavina</h1>
|
||||
</div>
|
||||
|
||||
<img class="slowpoke-moves" src="/images/slowpoke_blinking.gif" alt="this slowpoke moves" width="250"/>
|
||||
|
||||
|
||||
<div class="login">
|
||||
|
||||
<form class="login__form" onsubmit="">
|
||||
<h1 class="login__title">Log In</h1>
|
||||
|
||||
<div class="login__inputs">
|
||||
<div class="login__box">
|
||||
<input type="text" id="login" placeholder="Login" required class="login__input"/>
|
||||
</div>
|
||||
|
||||
<div class="login__box">
|
||||
<input type="password" placeholder="Password" required class="login__input"
|
||||
on:input=move |ev| { set_pwd(event_target_value(&ev))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="login__button">Start messaging</button>
|
||||
|
||||
<div class="login__register">
|
||||
Dont have an account? <a href="#">Register</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<form class="login__form" onsubmit="">
|
||||
<h1 class="login__title">Log In</h1>
|
||||
|
||||
<div class="login__inputs">
|
||||
<div class="login__box">
|
||||
<input type="text" id="login" placeholder="Login" required class="login__input"/>
|
||||
</div>
|
||||
|
||||
<div class="login__box">
|
||||
<input type="password" placeholder="Password" required class="login__input"
|
||||
on:input=move |ev| { set_pwd(event_target_value(&ev))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit" class="login__button">Start messaging</button>
|
||||
|
||||
<div class="login__register">
|
||||
Dont have an account? <a href="#">Register</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
async function newPlayer(name, password) {
|
||||
const urlCreatePlayer = 'http://127.0.0.1:8080/mgmt/create_player';
|
||||
const urlSetPassword = 'http://127.0.0.1:8080/mgmt/set_password';
|
||||
|
||||
const createQuery = {
|
||||
name: name
|
||||
};
|
||||
|
||||
try {
|
||||
const createResponse = await fetch(urlCreatePlayer, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(createQuery)
|
||||
});
|
||||
|
||||
if (!createResponse.ok) {
|
||||
throw new Error(`Ошибка создания игрока: ${createResponse.statusText}`);
|
||||
}
|
||||
|
||||
const setPasswordQuery = {
|
||||
player_name: name,
|
||||
password: password
|
||||
};
|
||||
|
||||
const passwordResponse = await fetch(urlSetPassword, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(setPasswordQuery)
|
||||
});
|
||||
|
||||
if (!passwordResponse.ok) {
|
||||
throw new Error(`Ошибка установки пароля: ${passwordResponse.statusText}`);
|
||||
}
|
||||
|
||||
console.log('Игрок успешно создан и пароль установлен.');
|
||||
} catch (error) {
|
||||
console.error('Произошла ошибка:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Пример вызова функции
|
||||
newPlayer('Igrogee', 'ПарольИгрока');
|
|
@ -0,0 +1,369 @@
|
|||
* {
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input::placeholder{
|
||||
opacity: 0.5;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
|
||||
input {
|
||||
font-size: 17px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
|
||||
/* background-image: linear-gradient(to bottom, #8221fa, #4221fa);
|
||||
*/ background-image: linear-gradient(to bottom, #3b116e, #221475);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-attachment:fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
font: 13px 'Arial', sans-serif;
|
||||
line-height: 1.5em;
|
||||
color: #FFFFFF;
|
||||
min-width: 399px;
|
||||
max-width: 799px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: grid;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 14px 14px 14px 14px;
|
||||
/* border: 0;
|
||||
*/ background: none;
|
||||
font-size: 99%;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
:focus {
|
||||
outline: 1px;
|
||||
}
|
||||
|
||||
.slowpoke-moves {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.shimmering-name {
|
||||
margin-top: 55px;
|
||||
color: rgb(218, 218, 218);
|
||||
font-family: monospace;
|
||||
font-size: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.welcome-to {
|
||||
margin-top: 30px;
|
||||
color: rgb(200, 200, 200, 0.6);
|
||||
font-family: monospace;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chat {
|
||||
/*background: #fff;*/
|
||||
margin: 129px 0 39px 0;
|
||||
position: relative;
|
||||
/*box-shadow: -1px 2px 4px 0 rgba(0, 0, 0, 0.2), -1px 25px 49px 0 rgba(0, 0, 0, 0.1);*/
|
||||
|
||||
}
|
||||
|
||||
.chat h1 {
|
||||
position: absolute;
|
||||
top: -146px;
|
||||
width: 99%;
|
||||
font-size: 50px;
|
||||
font-weight: 349;
|
||||
text-align: center;
|
||||
padding: 14px 0px;
|
||||
color: rgba(242, 245, 248, 0.479);
|
||||
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 0;
|
||||
padding: 14px 14px 14px 59px;
|
||||
list-style: none;
|
||||
border-radius: 20px;
|
||||
|
||||
}
|
||||
|
||||
.message li {
|
||||
position: relative;
|
||||
font-size: 23px;
|
||||
border-bottom: 0px solid #ededed;
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.enter-message {
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
width: 800px;
|
||||
margin: 0;
|
||||
font-size: 23px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
|
||||
border-radius: 25px;
|
||||
|
||||
padding: 15px 15px 15px 59px;
|
||||
border: none;
|
||||
background: #ededed;
|
||||
}
|
||||
|
||||
.message li label {
|
||||
word-break: break-all;
|
||||
padding: 14px 14px 14px 59px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color -0.6s;
|
||||
}
|
||||
|
||||
/* Styles for the remove button */
|
||||
.message li .remove {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: 25px;
|
||||
bottom: -1px;
|
||||
width: 39px;
|
||||
height: 39px;
|
||||
font-size: 29px;
|
||||
color: #cc9a9a;
|
||||
transition: color -0.2s ease-out;
|
||||
}
|
||||
|
||||
/* Hover styles for the remove button */
|
||||
.message li .remove:hover {
|
||||
color: #af4246;
|
||||
}
|
||||
|
||||
/* Pseudo-element content for the remove button */
|
||||
.message li .remove:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
/* Show the remove button on hover */
|
||||
.message li:hover .remove {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/*=============== VARIABLES CSS ===============*/
|
||||
:root {
|
||||
/*========== Colors ==========*/
|
||||
/*Color mode HSL(hue, saturation, lightness)*/
|
||||
--white-color: hsl(0, 0%, 100%);
|
||||
--black-color: hsl(0, 0%, 0%);
|
||||
|
||||
/*========== Font and typography ==========*/
|
||||
/*.5rem = 8px | 1rem = 16px ...*/
|
||||
--body-font: "Poppins", sans-serif;
|
||||
--h1-font-size: 2rem;
|
||||
--normal-font-size: 1rem;
|
||||
--small-font-size: .813rem;
|
||||
}
|
||||
|
||||
/*=============== BASE ===============*/
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
/* margin: 0; */
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: var(--body-font);
|
||||
font-size: var(--normal-font-size);
|
||||
}
|
||||
|
||||
|
||||
/*=============== LOGIN ===============*/
|
||||
.login {
|
||||
position: relative;
|
||||
margin-top: -6px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.login__bg {
|
||||
position: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.login__form {
|
||||
position: center;
|
||||
background-color: hsla(0, 0%, 100%, .01);
|
||||
border: 2px solid hsla(0, 0%, 100%, .7);
|
||||
padding: 2.5rem 1rem;
|
||||
color: var(--white-color);
|
||||
border-radius: 1rem;
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.login__title {
|
||||
text-align: center;
|
||||
font-size: var(--h1-font-size);
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.login__inputs,
|
||||
.login__box {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.login__inputs {
|
||||
row-gap: 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 50px
|
||||
|
||||
}
|
||||
|
||||
.login__box {
|
||||
grid-template-columns: 1fr max-content;
|
||||
column-gap: .75rem;
|
||||
align-items: center;
|
||||
border: 2px solid hsla(0, 0%, 100%, .7);
|
||||
padding-inline: 1.25rem;
|
||||
border-radius: 4rem;
|
||||
}
|
||||
|
||||
.login__input,
|
||||
.login__button {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.login__input {
|
||||
width: 100%;
|
||||
background: none;
|
||||
color: var(--white-color);
|
||||
padding-block: 1rem;
|
||||
}
|
||||
|
||||
.login__input::placeholder {
|
||||
color: var(--white-color);
|
||||
}
|
||||
|
||||
.login__box i {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.login__check,
|
||||
.login__check-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login__check {
|
||||
margin-bottom: 1rem;
|
||||
font-size: var(--small-font-size);
|
||||
}
|
||||
|
||||
.login__check-box {
|
||||
column-gap: .5rem;
|
||||
}
|
||||
|
||||
.login__check-input {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
accent-color: var(--white-color);
|
||||
}
|
||||
|
||||
.login__forgot {
|
||||
color: var(--white-color);
|
||||
}
|
||||
|
||||
.login__forgot:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.login__button {
|
||||
margin-top: 30px;
|
||||
|
||||
width: 100%;
|
||||
padding: 1.1rem;
|
||||
margin-bottom: 2rem;
|
||||
|
||||
opacity: 1.0;
|
||||
transition: 0.5s;
|
||||
|
||||
border: 2px solid black;
|
||||
color: white;
|
||||
|
||||
border-color: #04AA6D;
|
||||
|
||||
border-radius: 4rem;
|
||||
font-weight: 500;
|
||||
|
||||
animation: fading-border-animation 4s linear infinite;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login__button:hover {
|
||||
background-color: white;
|
||||
color: black;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes fading-border-animation {
|
||||
0% {border-color:rgba(255,255,255,0.3);}
|
||||
50% {border-color:rgba(255,255,255,1.0);}
|
||||
100% {border-color:rgba(255,255,255,0.3);}
|
||||
}
|
||||
|
||||
.login__register {
|
||||
font-size: var(--small-font-size);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login__register a {
|
||||
color: var(--white-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.login__register a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*=============== BREAKPOINTS ===============*/
|
||||
/* For medium devices */
|
||||
@media screen and (min-width: 576px) {
|
||||
.login {
|
||||
justify-content: center;
|
||||
}
|
||||
.login__form {
|
||||
width: 420px;
|
||||
padding-inline: 2.5rem;
|
||||
}
|
||||
.login__title {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 100 KiB |
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JsBook</title>
|
||||
|
||||
<style>
|
||||
.active {
|
||||
background-color: green;
|
||||
|
||||
}
|
||||
|
||||
button {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: medium;
|
||||
|
||||
}
|
||||
|
||||
nav {
|
||||
position: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section>
|
||||
<img id="output" src="../images/1.png" alt="">
|
||||
</section>
|
||||
|
||||
<nav>
|
||||
<button id="1" class="active">1</button>
|
||||
<button id="2">2</button>
|
||||
<button id="3">3</button>
|
||||
</nav>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
const output = document.getElementById("output");
|
||||
const buttons = document.querySelectorAll('nav button');
|
||||
console.log(buttons);
|
||||
|
||||
let active = buttons[0];
|
||||
console.log(active);
|
||||
|
||||
function showImage() {
|
||||
current = this;
|
||||
|
||||
output.src = '../images/' + this.id + '.jpg';
|
||||
buttons.forEach ( (el) => {
|
||||
el == this ? el.className = 'active' : el.className = ''
|
||||
}
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
buttons.forEach (
|
||||
(el) => {
|
||||
el.addEventListener('click', showImage)
|
||||
}
|
||||
)
|
||||
</script>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JsBook</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Пересчет величин</h1>
|
||||
<script type="text/javascript">
|
||||
const ins = window.prompt("Дюймы");
|
||||
const cens = ins * 2.54;
|
||||
window.document.write('<p>', cens, '</p>');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JsBook</title>
|
||||
|
||||
|
||||
<style>
|
||||
* {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-decoration:wavy;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Список</h1>
|
||||
<h2>fsdfss</h2>
|
||||
<script type="text/javascript">
|
||||
function listValues() {
|
||||
window.document.write('<ul>');
|
||||
for (i=0; i<arguments.length; i++){
|
||||
window.document.write('<li>', arguments[i], '</li>');
|
||||
console.log(arguments[i])};
|
||||
window.document.write('</ul>');
|
||||
}
|
||||
|
||||
listValues('Html', 'Css', 'Js', 'keke', 'sdew');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JsBook</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe src="example2.html" frameborder="1"></iframe>
|
||||
<input type="date">
|
||||
<h1>Список</h1>
|
||||
<script type="text/javascript">
|
||||
let person = {
|
||||
"keke": 100,
|
||||
"lol": "lol_value",
|
||||
}
|
||||
|
||||
for (i in person){
|
||||
document.write('<br/>', i, ': ', person[i]);
|
||||
console.log('----------------')
|
||||
console.log(person[i]);}
|
||||
|
||||
throw new TypeError('LLLLLLL')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
var x = document.getElementById("login");
|
||||
var y = document.getElementById("register");
|
||||
var z = document.getElementById("btn");
|
||||
|
||||
function register_form() {
|
||||
x.style.left = "-400px";
|
||||
y.style.left = "50px";
|
||||
z.style.left = "120px";
|
||||
}
|
||||
|
||||
function login_form() {
|
||||
x.style.left = "50px";
|
||||
y.style.left = "450px";
|
||||
z.style.left = "0";
|
||||
}
|
||||
|
||||
document.getElementById("login").addEventListener("submit", async function(event) {
|
||||
|
||||
var username = document.getElementById("login_input").value;
|
||||
var password = document.getElementById("password_input").value;
|
||||
|
||||
await newPlayer(username, password);
|
||||
|
||||
});
|
||||
|
||||
const host = '127.0.0.1'
|
||||
|
||||
// Функция newPlayer
|
||||
async function newPlayer(name, password) {
|
||||
const urlCreatePlayer = 'http://'+host+':8080/mgmt/create_player';
|
||||
const urlSetPassword = 'http://'+host+':8080/mgmt/set_password';
|
||||
|
||||
console.info(urlCreatePlayer);
|
||||
const createQuery = {
|
||||
name: name
|
||||
};
|
||||
|
||||
try {
|
||||
alert('Ready?');
|
||||
|
||||
fetch(urlCreatePlayer, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(createQuery)
|
||||
});
|
||||
|
||||
alert('User created');
|
||||
|
||||
const setPasswordQuery = {
|
||||
player_name: name,
|
||||
password: password
|
||||
};
|
||||
|
||||
fetch(urlSetPassword, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(setPasswordQuery)
|
||||
});
|
||||
|
||||
alert('Password setted');
|
||||
console.info('Игрок успешно создан и пароль установлен.');
|
||||
} catch (error) {
|
||||
console.error(`Произошла ошибка: ${error}`);
|
||||
}
|
||||
|
||||
alert('End of creation');
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="test_style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="hero">
|
||||
<div class="form-box">
|
||||
<div class="button-box">
|
||||
<div id="btn"></div>
|
||||
<button type="button" class="log-reg-button" onclick="login_form()">Log In</button>
|
||||
<button type="button" class="log-reg-button" onclick="register_form()">Register</button>
|
||||
</div>
|
||||
|
||||
<div class="social-icons">
|
||||
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||
<img src="../images/telegram-icon-2048x2048-l6ni6sux.png" alt="">
|
||||
</div>
|
||||
|
||||
<form id="login" class="input-group">
|
||||
<input type="text" id="login_input" class="input-field" placeholder="Login" required>
|
||||
<input type="text" id="password_input" class="input-field" placeholder="Password" required>
|
||||
<input type="checkbox" class="checkbox"><span>Remember Password</span>
|
||||
<button type="submit" class="submit-btn">Log In</button>
|
||||
</form>
|
||||
|
||||
<form id="register" class="input-group">
|
||||
<input type="text" class="input-field" placeholder="Login" required>
|
||||
<input type="email" class="input-field" placeholder="Email" required>
|
||||
<input type="text" class="input-field" placeholder="Password" required>
|
||||
<input type="checkbox" class="checkbox"><span>I argee to the terms</span>
|
||||
<button type="submit" class="submit-btn">Register</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="js_script.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,119 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.hero {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-image: url("http://127.0.0.1:3030/images/rain.jpg");
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 380px;
|
||||
height: 480px;
|
||||
position: relative;
|
||||
margin: 6% auto;
|
||||
background: rgb(255,255,255, 0.9);;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(16px);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
width: 220px;
|
||||
margin: 35px auto;
|
||||
position: relative;
|
||||
box-shadow: 0 0 20px 9px #ff61241f;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.log-reg-button {
|
||||
padding: 10px 30px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#btn {
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
background: linear-gradient(to right, #ff105f, #ffad06);
|
||||
border-radius: 30px;
|
||||
transition: .5s;
|
||||
}
|
||||
|
||||
.social-icons {
|
||||
margin: 30px auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.social-icons img {
|
||||
width: 30px;
|
||||
margin: 0 12px;
|
||||
box-shadow: 0 0 20px 0 #7f7f7f2d;
|
||||
cursor: pointer;
|
||||
filter: saturate(1)
|
||||
}
|
||||
|
||||
.input-group{
|
||||
top: 180px;
|
||||
position: absolute;
|
||||
width: 280px;
|
||||
transition: .5s;
|
||||
}
|
||||
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
margin: 5px 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-top: 0;
|
||||
border-bottom: 1px solid #999;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 85%;
|
||||
padding: 10px 30px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: auto;
|
||||
background: linear-gradient(to right, #ff105f, #ffad06);
|
||||
border: 0;
|
||||
outline: none;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
margin: 30px 10px 30px 0;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #777;
|
||||
font-size: 12px;
|
||||
bottom: 68px;
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
||||
#login {
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
#register {
|
||||
left: 450px;
|
||||
}
|