This commit is contained in:
Gvidas Juknevičius 2025-09-02 19:41:06 +03:00
commit d23055a0bf
Signed by: MCorange
GPG Key ID: 5BE6B533CB76FE86
17 changed files with 1608 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target
package-lock.json
node_modules/
build/

1324
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "persmgr-gui"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0.99"
askama = "0.14.0"
axum = "0.8.4"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.143"
tokio = { version = "1.47.1", features = ["full"] }
toml = "0.9.5"
tower = { version = "0.5.2", features = ["full"] }
tower-http = { version = "0.6.6", features = ["full"] }
tracing = "0.1.41"
tracing-subscriber = "0.3.20"

14
README.md Normal file
View File

@ -0,0 +1,14 @@
Dashboard
Roster
Management (with the right permissions only)
Documents
User (something shorter than personal file)
(user icon) (dropdown)
- Account
- Preferences
- Logout

19
persmgr-gui-rs/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "persmgr-gui"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0.99"
image = "0.25.7"
reqwest = { version = "0.12.23", features = ["json", "blocking"] }
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.143"
slint = { version = "1.12.1", features = ["gettext", "log", "serde", "image-default-formats"] }
tokio = "1.47.1"
toml = "0.9.5"
tracing = "0.1.41"
[build-dependencies]
slint-build = "1.12.1"

3
persmgr-gui-rs/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
slint_build::compile("ui/main.slint").unwrap();
}

View File

@ -0,0 +1,12 @@
slint::include_modules!();
fn main() {
let app = MainWindow::new().unwrap();
// connect callback
app.on_clicked(|| {
println!("Button was clicked owo");
});
app.run().unwrap();
}

View File

@ -0,0 +1,24 @@
import { Button } from "std-widgets.slint";
export component MainWindow inherits Window {
width: 400px;
height: 300px;
title: "My Slint App :3";
VerticalLayout {
Text {
text: "Hello nya~ from Slint!";
horizontal-alignment: center;
}
Button {
text: "Click me!";
clicked => {
root.clicked();
}
}
}
callback clicked();
}

View File

@ -0,0 +1,54 @@
import { Button } from "std-widgets.slint";
export component TopNavBar inherits HorizontalLayout {
height: 50px;
spacing: 16px;
padding-left: 16px;
padding-right: 16px;
// Permission flag for Management tab
in property <bool> is_officer: false;
// callbacks for tabs
callback dashboard_clicked();
callback roster_clicked();
callback management_clicked();
callback documents_clicked();
callback profile_clicked();
callback user_account_clicked();
callback user_preferences_clicked();
callback user_logout_clicked();
Button {
text: "Dashboard";
clicked() => {
root.dashboard_clicked();
}
}
Button {
text: "Roster";
clicked() => {
root.roster_clicked();
}
}
Button {
text: "Management";
clicked() => {
root.management_clicked();
}
}
Button {
text: "Documents";
clicked() => {
root.documents_clicked();
}
}
Button {
text: "Your file";
clicked() => {
root.dashboard_clicked();
}
}
}

38
res/css/global.css Normal file
View File

@ -0,0 +1,38 @@
:root {
--bg-color-ll: #535353;
--bg-color-l: #434343;
--bg-color: #323232;
--bg-color-d: #292929;
--bg-color-dd: #212121;
}
body {
background: var(--bg-color);
font-family: Arial, Helvetica, sans-serif;
}
#topnav {
width: 100%;
height: 10%;
background: var(--bg-color-l);
display: flex;
}
.topnav_button {
padding: 1rem 3rem;
margin: 3px 10px;
background: var(--bg-color-ll);
border: 2px solid var(--bg-color);
border-radius: 10px;
}
.topnav_button a {
text_decoration: none;
}
.topnav_button:hover {
cursor: pointer
}

BIN
res/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

11
src/api/mod.rs Normal file
View File

@ -0,0 +1,11 @@
use axum::{Router, http::StatusCode, routing::get};
async fn root() -> (StatusCode, &'static str) {
(StatusCode::OK, "We Good twin :3c")
}
pub fn register_routes() -> Router {
let router = Router::new().route("/", get(root));
Router::new().nest("/api", router)
}

30
src/main.rs Normal file
View File

@ -0,0 +1,30 @@
use axum::Router;
use tower::ServiceBuilder;
use tower_http::{services::ServeDir, trace::TraceLayer};
use tracing::{info, level_filters::LevelFilter};
use tracing_subscriber::FmtSubscriber;
mod api;
mod pages;
#[tokio::main]
async fn main() {
let sub = FmtSubscriber::builder()
.with_max_level(LevelFilter::DEBUG)
.finish();
tracing::subscriber::set_global_default(sub).unwrap();
info!("Server starting");
let app = Router::new()
.merge(pages::register_routes())
.merge(api::register_routes())
.fallback_service(ServiceBuilder::new().service(ServeDir::new("res")))
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()));
let laddr = "0.0.0.0:8080";
let sock = tokio::net::TcpListener::bind(laddr).await.unwrap();
info!("Listening on http://{laddr}");
axum::serve(sock, app).await.unwrap();
}

12
src/pages/index.rs Normal file
View File

@ -0,0 +1,12 @@
use askama::Template;
use axum::{http::StatusCode, response::Html};
#[derive(Debug, Template, Clone)]
#[template(path = "index.html")]
pub struct PageTemplate {}
pub async fn page() -> (StatusCode, Html<String>) {
let page = PageTemplate {};
(StatusCode::OK, Html(page.render().unwrap()))
}

8
src/pages/mod.rs Normal file
View File

@ -0,0 +1,8 @@
use askama::Template;
use axum::{Router, routing::get};
pub mod index;
pub fn register_routes() -> Router {
Router::new().route("/", get(index::page))
}

27
templates/base.html Normal file
View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title>
<link href="css/global.css" rel="stylesheet">
{% block headers %}{% endblock %}
</head>
<body>
<div id="topnav">
<div class="topnav_button" onclick="location.href='/'">
Dashboard
</div>
<div class="topnav_button" onclick="location.href='/roster'">
Roster
</div>
<div class="topnav_button" onclick="location.href='/events'">
Events
</div>
<div class="topnav_button" onclick="location.href='/documents'">
Documents
</div>
{% block content %}{% endblock %}
</div>
</body>
</html>

11
templates/index.html Normal file
View File

@ -0,0 +1,11 @@
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block headers %}
{% endblock %}
{% block content %}
<h1>Hello!!!!!!!</h1>
{% endblock %}