Darkmode hinzugefügt
This commit is contained in:
6
app.py
6
app.py
@@ -12,7 +12,7 @@ from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = "dev-secret-key"
|
||||
APP_VERSION = "1.5.0"
|
||||
APP_VERSION = "2.1.0"
|
||||
DATABASE = Path(__file__).with_name("inventory.db")
|
||||
LOGFILE = Path(__file__).with_name("inventory.log")
|
||||
|
||||
@@ -40,8 +40,8 @@ PRINT_DESCRIPTIONS = {
|
||||
}
|
||||
|
||||
INPUT_PLACEHOLDERS = {
|
||||
"chip": "z. B. CHIP-1001",
|
||||
"parking_card": "z. B. PARK-2001",
|
||||
"chip": "z. B. 100",
|
||||
"parking_card": "z. B. 200199887755123",
|
||||
"pool_vehicle": "z. B. GZ-CC-123",
|
||||
}
|
||||
|
||||
|
||||
@@ -1042,3 +1042,83 @@
|
||||
2026-05-19 22:07:47,705 INFO 127.0.0.1 - - [19/May/2026 22:07:47] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:07:50,763 INFO 127.0.0.1 - - [19/May/2026 22:07:50] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:07:50,786 INFO 127.0.0.1 - - [19/May/2026 22:07:50] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:28:58,481 INFO [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* Running on all addresses (0.0.0.0)
|
||||
* Running on http://127.0.0.1:5006
|
||||
* Running on http://192.168.10.191:5006
|
||||
2026-05-19 22:28:58,484 INFO [33mPress CTRL+C to quit[0m
|
||||
2026-05-19 22:28:58,488 INFO * Restarting with stat
|
||||
2026-05-19 22:28:58,657 WARNING * Debugger is active!
|
||||
2026-05-19 22:28:58,672 INFO * Debugger PIN: 428-899-358
|
||||
2026-05-19 22:29:01,471 INFO 127.0.0.1 - - [19/May/2026 22:29:01] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:29:01,519 INFO 127.0.0.1 - - [19/May/2026 22:29:01] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:29:12,441 INFO 127.0.0.1 - - [19/May/2026 22:29:12] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:29:12,462 INFO 127.0.0.1 - - [19/May/2026 22:29:12] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:29:16,459 INFO 127.0.0.1 - - [19/May/2026 22:29:16] "GET /assign HTTP/1.1" 200 -
|
||||
2026-05-19 22:29:16,483 INFO 127.0.0.1 - - [19/May/2026 22:29:16] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:29:17,805 INFO 127.0.0.1 - - [19/May/2026 22:29:17] "GET /return HTTP/1.1" 200 -
|
||||
2026-05-19 22:29:17,825 INFO 127.0.0.1 - - [19/May/2026 22:29:17] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:29:19,721 INFO 127.0.0.1 - - [19/May/2026 22:29:19] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:29:19,745 INFO 127.0.0.1 - - [19/May/2026 22:29:19] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:30:32,956 INFO 127.0.0.1 - - [19/May/2026 22:30:32] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:30:32,982 INFO 127.0.0.1 - - [19/May/2026 22:30:32] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:31:28,576 INFO 127.0.0.1 - - [19/May/2026 22:31:28] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:31:28,597 INFO 127.0.0.1 - - [19/May/2026 22:31:28] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:33:58,615 INFO 127.0.0.1 - - [19/May/2026 22:33:58] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:33:58,647 INFO 127.0.0.1 - - [19/May/2026 22:33:58] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:34:01,025 INFO 127.0.0.1 - - [19/May/2026 22:34:01] "GET /assign HTTP/1.1" 200 -
|
||||
2026-05-19 22:34:01,047 INFO 127.0.0.1 - - [19/May/2026 22:34:01] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:34:02,985 INFO 127.0.0.1 - - [19/May/2026 22:34:02] "GET /return HTTP/1.1" 200 -
|
||||
2026-05-19 22:34:03,006 INFO 127.0.0.1 - - [19/May/2026 22:34:03] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:34:04,099 INFO 127.0.0.1 - - [19/May/2026 22:34:04] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:34:04,124 INFO 127.0.0.1 - - [19/May/2026 22:34:04] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:35:27,210 INFO 127.0.0.1 - - [19/May/2026 22:35:27] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:35:27,241 INFO 127.0.0.1 - - [19/May/2026 22:35:27] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:35:47,127 INFO 127.0.0.1 - - [19/May/2026 22:35:47] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:35:47,155 INFO 127.0.0.1 - - [19/May/2026 22:35:47] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:35:48,755 INFO 127.0.0.1 - - [19/May/2026 22:35:48] "GET /assign HTTP/1.1" 200 -
|
||||
2026-05-19 22:35:48,779 INFO 127.0.0.1 - - [19/May/2026 22:35:48] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:35:49,726 INFO 127.0.0.1 - - [19/May/2026 22:35:49] "GET /return HTTP/1.1" 200 -
|
||||
2026-05-19 22:35:49,749 INFO 127.0.0.1 - - [19/May/2026 22:35:49] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:35:54,822 INFO 127.0.0.1 - - [19/May/2026 22:35:54] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:35:54,841 INFO 127.0.0.1 - - [19/May/2026 22:35:54] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:36:53,033 INFO 127.0.0.1 - - [19/May/2026 22:36:53] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:36:53,056 INFO 127.0.0.1 - - [19/May/2026 22:36:53] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:37:02,607 INFO 127.0.0.1 - - [19/May/2026 22:37:02] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:37:02,640 INFO 127.0.0.1 - - [19/May/2026 22:37:02] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:37:04,683 INFO 127.0.0.1 - - [19/May/2026 22:37:04] "GET /assign HTTP/1.1" 200 -
|
||||
2026-05-19 22:37:04,707 INFO 127.0.0.1 - - [19/May/2026 22:37:04] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:37:06,184 INFO 127.0.0.1 - - [19/May/2026 22:37:06] "GET /return HTTP/1.1" 200 -
|
||||
2026-05-19 22:37:06,206 INFO 127.0.0.1 - - [19/May/2026 22:37:06] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:37:07,536 INFO 127.0.0.1 - - [19/May/2026 22:37:07] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:37:07,555 INFO 127.0.0.1 - - [19/May/2026 22:37:07] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:46,578 INFO 127.0.0.1 - - [19/May/2026 22:38:46] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:46,606 INFO 127.0.0.1 - - [19/May/2026 22:38:46] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:50,867 INFO 127.0.0.1 - - [19/May/2026 22:38:50] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:50,895 INFO 127.0.0.1 - - [19/May/2026 22:38:50] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:52,374 INFO 127.0.0.1 - - [19/May/2026 22:38:52] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:52,395 INFO 127.0.0.1 - - [19/May/2026 22:38:52] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:57,770 INFO 127.0.0.1 - - [19/May/2026 22:38:57] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:57,793 INFO 127.0.0.1 - - [19/May/2026 22:38:57] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:58,294 INFO 127.0.0.1 - - [19/May/2026 22:38:58] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:58,314 INFO 127.0.0.1 - - [19/May/2026 22:38:58] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:38:59,411 INFO 127.0.0.1 - - [19/May/2026 22:38:59] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:38:59,433 INFO 127.0.0.1 - - [19/May/2026 22:38:59] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:31,748 INFO 127.0.0.1 - - [19/May/2026 22:40:31] "GET /users/new HTTP/1.1" 200 -
|
||||
2026-05-19 22:40:31,780 INFO 127.0.0.1 - - [19/May/2026 22:40:31] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:33,164 INFO 127.0.0.1 - - [19/May/2026 22:40:33] "GET /assign HTTP/1.1" 200 -
|
||||
2026-05-19 22:40:33,189 INFO 127.0.0.1 - - [19/May/2026 22:40:33] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:34,888 INFO 127.0.0.1 - - [19/May/2026 22:40:34] "GET /return HTTP/1.1" 200 -
|
||||
2026-05-19 22:40:34,909 INFO 127.0.0.1 - - [19/May/2026 22:40:34] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:37,420 INFO 127.0.0.1 - - [19/May/2026 22:40:37] "[32mGET /logout HTTP/1.1[0m" 302 -
|
||||
2026-05-19 22:40:37,429 INFO 127.0.0.1 - - [19/May/2026 22:40:37] "GET /login HTTP/1.1" 200 -
|
||||
2026-05-19 22:40:37,449 INFO 127.0.0.1 - - [19/May/2026 22:40:37] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:37,457 INFO 127.0.0.1 - - [19/May/2026 22:40:37] "[36mGET /static/favicon.ico HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:43,940 INFO 127.0.0.1 - - [19/May/2026 22:40:43] "[32mPOST /login HTTP/1.1[0m" 302 -
|
||||
2026-05-19 22:40:43,967 INFO 127.0.0.1 - - [19/May/2026 22:40:43] "GET / HTTP/1.1" 200 -
|
||||
2026-05-19 22:40:43,992 INFO 127.0.0.1 - - [19/May/2026 22:40:43] "[36mGET /static/cancom.svg HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:40:44,005 INFO 127.0.0.1 - - [19/May/2026 22:40:44] "[36mGET /static/favicon.ico HTTP/1.1[0m" 304 -
|
||||
2026-05-19 22:42:50,799 INFO * Detected change in '/Users/erik/Documents/DEV/Key Verwaltung/app.py', reloading
|
||||
2026-05-19 22:42:50,836 INFO * Restarting with stat
|
||||
2026-05-19 22:42:51,090 WARNING * Debugger is active!
|
||||
2026-05-19 22:42:51,115 INFO * Debugger PIN: 428-899-358
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
||||
<script>
|
||||
(() => {
|
||||
const storedTheme = window.localStorage.getItem("keyadmin-theme");
|
||||
const theme = storedTheme === "dark" || storedTheme === "light" ? storedTheme : "light";
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
})();
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--ccm-bg: #f4f6f8;
|
||||
@@ -78,6 +85,94 @@
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2.5rem;
|
||||
min-height: 2.5rem;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] {
|
||||
--ccm-bg: #15181d;
|
||||
--ccm-text: #e5e7eb;
|
||||
--ccm-header: #0f1720;
|
||||
--ccm-surface: #15181d;
|
||||
--ccm-border: #2b3440;
|
||||
--ccm-muted: #9aa4b2;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] body {
|
||||
background-color: var(--ccm-bg);
|
||||
color: var(--ccm-text);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .card,
|
||||
[data-bs-theme="dark"] .dropdown-menu,
|
||||
[data-bs-theme="dark"] .table,
|
||||
[data-bs-theme="dark"] .table-responsive,
|
||||
[data-bs-theme="dark"] .login-card,
|
||||
[data-bs-theme="dark"] .page-shell,
|
||||
[data-bs-theme="dark"] .form-card {
|
||||
background-color: var(--ccm-bg);
|
||||
color: var(--ccm-text);
|
||||
border-color: var(--ccm-border);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .page-section-title,
|
||||
[data-bs-theme="dark"] .grid > .card {
|
||||
background-color: var(--ccm-bg);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .card-table-shell {
|
||||
background-color: var(--ccm-bg);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .details th,
|
||||
[data-bs-theme="dark"] .details td,
|
||||
[data-bs-theme="dark"] .table > :not(caption) > * > * {
|
||||
border-color: var(--ccm-border);
|
||||
color: var(--ccm-text);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-control,
|
||||
[data-bs-theme="dark"] .form-select {
|
||||
background-color: #11161d;
|
||||
color: var(--ccm-text);
|
||||
border-color: var(--ccm-border);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .form-control::placeholder,
|
||||
[data-bs-theme="dark"] .muted,
|
||||
[data-bs-theme="dark"] .page-section-title p,
|
||||
[data-bs-theme="dark"] .app-footer,
|
||||
[data-bs-theme="dark"] .table thead th {
|
||||
color: var(--ccm-muted);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .button-secondary {
|
||||
background: #11161d;
|
||||
color: var(--ccm-text);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .nav-surface .btn-white {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
color: #ffffff;
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .nav-surface .btn.active {
|
||||
background-color: rgba(255, 255, 255, 0.92);
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] .theme-toggle {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.navbar-brand-wordmark strong {
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
@@ -260,6 +355,11 @@
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.card-table-shell {
|
||||
border-radius: 0 0 1rem 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-table .btn {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -500,6 +600,9 @@
|
||||
<div class="navbar-nav flex-row order-md-last top-actions">
|
||||
{% if g.current_staff %}
|
||||
<span class="nav-link disabled">{{ g.current_staff.full_name }} ({{ g.current_staff.role }})</span>
|
||||
<button type="button" class="btn btn-outline-secondary me-2 theme-toggle" id="theme-toggle" aria-label="Darkmode umschalten" title="Darkmode umschalten">
|
||||
<i class="ti ti-moon"></i>
|
||||
</button>
|
||||
<a class="btn btn-outline-secondary" href="{{ url_for('logout') }}"><i class="ti ti-logout me-1"></i>Abmelden</a>
|
||||
{% else %}
|
||||
<a class="btn btn-primary" href="{{ url_for('login') }}"><i class="ti ti-login me-1"></i>Login</a>
|
||||
@@ -550,6 +653,25 @@
|
||||
</div>
|
||||
<script>
|
||||
window.addEventListener("load", () => {
|
||||
const themeToggle = document.getElementById("theme-toggle");
|
||||
const root = document.documentElement;
|
||||
|
||||
const syncThemeToggle = () => {
|
||||
const theme = root.getAttribute("data-bs-theme") || "light";
|
||||
if (!themeToggle) return;
|
||||
themeToggle.innerHTML = theme === "dark" ? '<i class="ti ti-sun"></i>' : '<i class="ti ti-moon"></i>';
|
||||
};
|
||||
|
||||
if (themeToggle) {
|
||||
syncThemeToggle();
|
||||
themeToggle.addEventListener("click", () => {
|
||||
const nextTheme = (root.getAttribute("data-bs-theme") || "light") === "dark" ? "light" : "dark";
|
||||
root.setAttribute("data-bs-theme", nextTheme);
|
||||
window.localStorage.setItem("keyadmin-theme", nextTheme);
|
||||
syncThemeToggle();
|
||||
});
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
document.querySelectorAll(".flash-stack .alert").forEach((element) => {
|
||||
if (element.classList.contains("alert-error") || element.classList.contains("alert-danger") || element.classList.contains("alert-import-errors")) {
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="card-header">
|
||||
<h2 class="card-title"><i class="ti ti-users me-1"></i>User</h2>
|
||||
</div>
|
||||
<div class="table-responsive table-wrap">
|
||||
<div class="table-responsive table-wrap card-table-shell">
|
||||
{% if users %}
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
@@ -126,7 +126,7 @@
|
||||
<div class="card-header">
|
||||
<h2 class="card-title"><i class="ti ti-history me-1"></i>Letzte Bewegungen</h2>
|
||||
</div>
|
||||
<div class="table-responsive table-wrap">
|
||||
<div class="table-responsive table-wrap card-table-shell">
|
||||
{% if transactions %}
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
@@ -165,7 +165,7 @@
|
||||
<div class="card-header">
|
||||
<h2 class="card-title"><i class="ti ti-file-text me-1"></i>Letzte Logeintraege</h2>
|
||||
</div>
|
||||
<div class="table-responsive table-wrap">
|
||||
<div class="table-responsive table-wrap card-table-shell">
|
||||
{% if recent_logs %}
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
|
||||
Reference in New Issue
Block a user