Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f3913dcfb | ||
|
|
31e98c0936 | ||
|
|
b404ff5bc9 | ||
|
|
c3b7321005 | ||
|
|
2a15f77f4f | ||
|
|
dfb031949b | ||
|
|
b030e133a2 | ||
|
|
810d554cb9 | ||
|
|
2e6bd2a781 | ||
|
|
390630886e | ||
|
|
0ee20e2833 | ||
|
|
b7f8df624c | ||
|
|
8a9c9efbcc | ||
|
|
c31375573f | ||
|
|
b2daed8e99 | ||
|
|
076bd6c545 | ||
|
|
a42897de9f | ||
|
|
3154e3de44 | ||
|
|
bf0197adae | ||
|
|
c6a4a24fb6 | ||
|
|
52387f7333 |
+2
-1
@@ -20,9 +20,10 @@ frontend/node_modules/
|
|||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
.idea/
|
||||||
|
|
||||||
|
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
.antigravitycli/
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ pub async fn get_current_user(
|
|||||||
/// - `404 Not Found` if user doesn't exist
|
/// - `404 Not Found` if user doesn't exist
|
||||||
/// - `500 Internal Server Error` if database error occurs
|
/// - `500 Internal Server Error` if database error occurs
|
||||||
pub async fn delete_user(
|
pub async fn delete_user(
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i16>,
|
||||||
State(data): State<Arc<AppState>>,
|
State(data): State<Arc<AppState>>,
|
||||||
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
||||||
let query = sqlx::query(r#"DELETE FROM users WHERE id = $1"#)
|
let query = sqlx::query(r#"DELETE FROM users WHERE id = $1"#)
|
||||||
@@ -414,32 +414,43 @@ pub async fn get_user_by_id(
|
|||||||
/// - Passwords are hashed using Argon2 before storage.
|
/// - Passwords are hashed using Argon2 before storage.
|
||||||
/// - This endpoint typically requires admin privileges (enforced by middleware).
|
/// - This endpoint typically requires admin privileges (enforced by middleware).
|
||||||
pub async fn update_user(
|
pub async fn update_user(
|
||||||
Path(id): Path<i32>,
|
Path(id): Path<i16>,
|
||||||
State(data): State<Arc<AppState>>,
|
State(data): State<Arc<AppState>>,
|
||||||
Json(body): Json<UserUpdateScheme>,
|
Json(body): Json<UserUpdateScheme>,
|
||||||
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
||||||
let argon = Argon2::default();
|
let update_result = if !body.new_pwd.is_empty() {
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let argon = Argon2::default();
|
||||||
let hashed_pwd = match argon.hash_password(body.new_pwd.clone().as_bytes(), &salt) {
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
Ok(h) => h.to_string(),
|
let hashed_pwd = match argon.hash_password(body.new_pwd.clone().as_bytes(), &salt) {
|
||||||
Err(e) => panic!("Error hashing {:}", e),
|
Ok(h) => h.to_string(),
|
||||||
};
|
Err(e) => panic!("Error hashing {:}", e),
|
||||||
|
};
|
||||||
|
|
||||||
let update_result = sqlx::query(r#"UPDATE users SET first_name = $1, last_name = $2, username = $3, pwd = $4, is_admin = $5 WHERE id = $6"#)
|
sqlx::query(r#"UPDATE users SET first_name = $1, last_name = $2, username = $3, pwd = $4, is_admin = $5 WHERE id = $6"#)
|
||||||
.bind(body.first_name.to_owned())
|
.bind(body.first_name.to_owned())
|
||||||
.bind(body.last_name.to_owned())
|
.bind(body.last_name.to_owned())
|
||||||
.bind(body.username.to_owned())
|
.bind(body.username.to_owned())
|
||||||
.bind(&hashed_pwd)
|
.bind(hashed_pwd)
|
||||||
.bind(body.make_admin.to_owned())
|
.bind(body.make_admin.to_owned())
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.execute(&data.db)
|
.execute(&data.db)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
} else {
|
||||||
(
|
sqlx::query(r#"UPDATE users SET first_name = $1, last_name = $2, username = $3, is_admin = $4 WHERE id = $5"#)
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
.bind(body.first_name.to_owned())
|
||||||
Json(json!({"status": "error", "message": format!("{:?}", e)})),
|
.bind(body.last_name.to_owned())
|
||||||
)
|
.bind(body.username.to_owned())
|
||||||
})?;
|
.bind(body.make_admin.to_owned())
|
||||||
|
.bind(id)
|
||||||
|
.execute(&data.db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
Json(json!({"status": "error", "message": format!("{:?}", e)})),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
if update_result.rows_affected() == 0 {
|
if update_result.rows_affected() == 0 {
|
||||||
let error_response = serde_json::json!({
|
let error_response = serde_json::json!({
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<link data-trunk rel="rust" data-bin="bin" />
|
<link data-trunk rel="rust" data-bin="bin" />
|
||||||
<link data-trunk rel="scss" href="src/styles/main.scss" />
|
<link data-trunk rel="scss" href="src/styles/main.scss" />
|
||||||
|
<link data-trunk rel="icon" href="src/assets/favicon.ico" type="image/x-icon" />
|
||||||
|
<link data-trunk rel="copy-dir" href="src/assets" />
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Yew App</title>
|
<title>Yew App</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -269,6 +269,7 @@ fn switch(route: Route) -> Html {
|
|||||||
pub fn app() -> Html {
|
pub fn app() -> Html {
|
||||||
html! {
|
html! {
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<basic_pages::Icon/>
|
||||||
<Switch<Route> render={switch} />
|
<Switch<Route> render={switch} />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub fn home_component() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div class="rundbg">
|
||||||
<crate::utilities::TicketCount/>
|
<crate::utilities::TicketCount/>
|
||||||
|
|
||||||
<p>{ "You are logged in as: " }</p>
|
<p>{ "You are logged in as: " }</p>
|
||||||
@@ -109,3 +109,10 @@ pub fn denied_component() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component(Icon)]
|
||||||
|
pub fn icon_component() -> Html {
|
||||||
|
html! {
|
||||||
|
<img src="assets/csg.png" class="csg-icon" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
let room_valid = (*room).is_some();
|
let room_valid = (*room).is_some();
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<form {onsubmit}>
|
<form class="rundbg" {onsubmit}>
|
||||||
<label>{ "Betreff:" }
|
<label>{ "Betreff:" }
|
||||||
<input type="text" value={(*betreff).clone()} oninput={betreff_change}/>
|
<input type="text" value={(*betreff).clone()} oninput={betreff_change}/>
|
||||||
</label>
|
</label>
|
||||||
@@ -313,7 +313,7 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
{
|
{
|
||||||
if !room_valid {
|
if !room_valid {
|
||||||
html! {
|
html! {
|
||||||
<p style="color: red;">{ "Ungültiger oder nicht erlaubter Raum (z. B. 101, K12, D5)" }</p>
|
<p class="warning" >{ "Ungültiger / nicht erlaubter Raum (z. B. 101, K12, D5)" }</p>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! {}
|
html! {}
|
||||||
@@ -664,9 +664,17 @@ pub fn all_tickets_component() -> Html {
|
|||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Error: {}", e) }</p> }
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<ul>
|
<ul class= "postits">
|
||||||
{ for tickets.iter().filter(|t| t.status != "Archived" && (if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| html! {
|
{ for tickets.iter().filter(|t| t.status != "Archived" && (if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| {
|
||||||
<div>
|
let status_class = match t.status.as_str() {
|
||||||
|
"ToDo" => "To-Do",
|
||||||
|
"InProgress" => "InProgress",
|
||||||
|
"Completed" => "Completed",
|
||||||
|
"Archived" => "Archived",
|
||||||
|
_ => "To-Do"
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<div class={classes!{status_class, "listbox"}}>
|
||||||
<li key={t.id.to_string()}>
|
<li key={t.id.to_string()}>
|
||||||
<Link<crate::Route> to={crate::Route::TicketById{id: t.id}}><h3>{ format!("{} - #{}", t.betreff, t.id) }</h3></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::TicketById{id: t.id}}><h3>{ format!("{} - #{}", t.betreff, t.id) }</h3></Link<crate::Route>>
|
||||||
<p>{ &t.description }</p>
|
<p>{ &t.description }</p>
|
||||||
@@ -680,7 +688,8 @@ pub fn all_tickets_component() -> Html {
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
})}
|
}})}
|
||||||
|
|
||||||
<Link<crate::Route> to={crate::Route::Ticket}>{ "Zurück zur Startseite" }</Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::Ticket}>{ "Zurück zur Startseite" }</Link<crate::Route>>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ pub fn register_component() -> Html {
|
|||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<form {onsubmit}>
|
<form {onsubmit} class="rundbg">
|
||||||
<label>{ "Vorname:" }
|
<label>{ "Vorname:" }
|
||||||
<input type="text" value={(*first_name).clone()} oninput={fn_change}/>
|
<input type="text" value={(*first_name).clone()} oninput={fn_change}/>
|
||||||
</label>
|
</label>
|
||||||
@@ -328,14 +328,16 @@ pub fn login_component() -> Html {
|
|||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<form {onsubmit}>
|
<div>
|
||||||
|
<h1 class="headline">{ "Anmeldung" }</h1>
|
||||||
|
<form {onsubmit} class="rundbg login">
|
||||||
<input
|
<input
|
||||||
placeholder="username"
|
placeholder="username"
|
||||||
value={(*username).clone()}
|
value={(*username).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
username.set(input.value());
|
username.set(input.value());
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
@@ -349,6 +351,7 @@ pub fn login_component() -> Html {
|
|||||||
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
||||||
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
if !error.is_empty() { <p style="color:red">{(*error).clone()}</p> }
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,9 +425,9 @@ pub fn all_users_component() -> Html {
|
|||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Error: {}", e) }</p> }
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<ul>
|
<ul class="postits">
|
||||||
{ for users.iter().map(|t| html! {
|
{ for users.iter().map(|t| html! {
|
||||||
<li key={t.id.to_string()}>
|
<li key={t.id.to_string()} class="listbox">
|
||||||
<Link<crate::Route> to={crate::Route::UserByID{id: t.id}}><h3>{ format!("{} {}- #{}", t.first_name, t.last_name, t.id) }</h3></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::UserByID{id: t.id}}><h3>{ format!("{} {}- #{}", t.first_name, t.last_name, t.id) }</h3></Link<crate::Route>>
|
||||||
</li>
|
</li>
|
||||||
})}
|
})}
|
||||||
@@ -563,6 +566,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
let last_name = (*last_name).clone();
|
let last_name = (*last_name).clone();
|
||||||
let username = (*username).clone();
|
let username = (*username).clone();
|
||||||
let make_admin = *make_admin;
|
let make_admin = *make_admin;
|
||||||
|
let new_pwd_state = new_pwd.clone();
|
||||||
let new_pwd = (*new_pwd).clone();
|
let new_pwd = (*new_pwd).clone();
|
||||||
|
|
||||||
saving.set(true);
|
saving.set(true);
|
||||||
@@ -597,6 +601,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
if let Ok(updated) = resp.json::<FilteredUser>().await {
|
if let Ok(updated) = resp.json::<FilteredUser>().await {
|
||||||
user_state.set(Some(updated));
|
user_state.set(Some(updated));
|
||||||
}
|
}
|
||||||
|
new_pwd_state.set(String::new());
|
||||||
save_success.set(true);
|
save_success.set(true);
|
||||||
}
|
}
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
$color-bg: #ffffff;
|
$color-bg: #ffffff;
|
||||||
$color-sidebar: #0f172a;
|
$color-sidebar: #570000;
|
||||||
$color-accent: #2563eb;
|
$color-accent: #2563eb;
|
||||||
$color-muted: #6b7280;
|
$color-muted: #6b7280;
|
||||||
$spacing-sm: 8px;
|
$spacing-sm: 8px;
|
||||||
$spacing-md: 16px;
|
$spacing-md: 16px;
|
||||||
$border-radius: 6px;
|
$border-radius: 6px;
|
||||||
|
$rundbgbackgroundcolor: #a0a0a0;
|
||||||
|
|||||||
@@ -130,7 +130,7 @@
|
|||||||
|
|
||||||
.room-bar {
|
.room-bar {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #f97316;
|
background-color: #570000;
|
||||||
transition: width 0.3s ease;
|
transition: width 0.3s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.headline {
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
color: #570000;
|
||||||
|
margin-top: 150px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
.csg-icon {
|
||||||
|
position: fixed;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
z-index: 9999;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,24 +4,26 @@
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
width: 260px;
|
width: 260px;
|
||||||
background: $color-sidebar;
|
background: $color-sidebar;
|
||||||
color: #fff;
|
color: #fffefe;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
padding: $spacing-md;
|
padding: $spacing-md;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: $spacing-sm; flex: 1; }
|
ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: $spacing-sm; flex: 1; }
|
||||||
|
|
||||||
a, .menu-toggle {
|
a, .menu-toggle {
|
||||||
color: #fff;
|
color: #ffffff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: block;
|
display: block;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
&:hover { background: rgba(255,255,255,0.04); }
|
&:hover { background: rgba(158, 45, 1, 0.842); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-toggle { background: transparent; border: none; text-align: left; width: 100%; cursor: pointer; }
|
.menu-toggle { background: #ff5a316c; border: none; text-align: left; width: 100%; cursor: pointer; }
|
||||||
|
|
||||||
.submenu {
|
.submenu {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
@@ -38,9 +40,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.logout-button {
|
.logout-button {
|
||||||
background: rgba(255,255,255,0.1);
|
background: rgba(255, 93, 43, 0.527);
|
||||||
color: #fff;
|
color: #ffffff;
|
||||||
border: 1px solid rgba(255,255,255,0.2);
|
border: 1px solid rgba(255, 255, 255, 0.801);
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -7,7 +7,53 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $spacing-sm;
|
gap: $spacing-sm;
|
||||||
|
|
||||||
.meta { color: $color-muted; font-size: 0.9rem; }
|
.meta { color: $color-muted; font-size: 0.9rem; }
|
||||||
.title { font-weight: 600; }
|
.title { font-weight: 600; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.listbox {
|
||||||
|
max-width: auto;
|
||||||
|
margin:0 0;
|
||||||
|
background-color: #90ff82;
|
||||||
|
background-color: $rundbgbackgroundcolor;
|
||||||
|
padding-bottom: 96px;
|
||||||
|
color: white;
|
||||||
|
padding-left: 32px;
|
||||||
|
padding-right: 32px;
|
||||||
|
padding-top: 96px;
|
||||||
|
border-radius: 20px;
|
||||||
|
border-color: #000000;
|
||||||
|
border-style: double;
|
||||||
|
box-shadow: 10px 10px 10px rgba(43, 43, 43, 0.8);
|
||||||
|
font-size: 26px;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
|
||||||
|
&.To-Do {
|
||||||
|
background-color: #b1003b;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.InProgress {
|
||||||
|
background-color: #fff385;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Completed {
|
||||||
|
background-color: #90ff82;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Archived {
|
||||||
|
background-color: #af69ee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.postits {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto auto;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 96px;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
color: #570000;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
@use "components/sidebar";
|
@use "components/sidebar";
|
||||||
@use "components/tickets";
|
@use "components/tickets";
|
||||||
@use "components/diagnostics";
|
@use "components/diagnostics";
|
||||||
|
@use "components/frontpage";
|
||||||
|
@use "components/home";
|
||||||
|
@use "components/icon";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: variables.$color-bg;
|
background: variables.$color-bg;
|
||||||
@@ -13,26 +16,102 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.admin { display: flex; }
|
.admin { display: flex; }
|
||||||
.content { flex: 1; padding: variables.$spacing-md; }
|
|
||||||
|
|
||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 100vh;
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 260px;
|
width: 260px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: variables.$spacing-md;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.sidebar { position: fixed; left: -100%; transition: left .2s; }
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: -100%;
|
||||||
|
transition: left .2s;
|
||||||
|
z-index: 1000;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
.sidebar.open { left: 0; }
|
.sidebar.open { left: 0; }
|
||||||
.content { margin-left: 0; }
|
.content { margin-left: 0; padding: variables.$spacing-md; box-sizing: border-box; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rundbg {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 40%;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: variables.$rundbgbackgroundcolor;
|
||||||
|
padding-bottom: 96px;
|
||||||
|
padding-left: 32px;
|
||||||
|
padding-right: 32px;
|
||||||
|
padding-top: 96px;
|
||||||
|
border-radius: 20px;
|
||||||
|
gap: 8px;
|
||||||
|
border-color: #000000;
|
||||||
|
border-style: double;
|
||||||
|
box-shadow: 20px 20px 10px rgb(43, 43, 43);
|
||||||
|
font-size: 26px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select, button, a {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
box-shadow: #6d6d6d;
|
||||||
|
box-shadow: 6px 6px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000000;
|
||||||
|
text-align: center;
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.login {
|
||||||
|
margin-top: 96px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.setup-form input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user