Update dashboard
This commit is contained in:
@@ -31,6 +31,13 @@ app.config['TEMPLATES_AUTO_RELOAD'] = os.environ.get('TEMPLATES_AUTO_RELOAD')
|
|||||||
# Initialize database
|
# Initialize database
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_company_name():
|
||||||
|
"""Make COMPANY_NAME available to all templates"""
|
||||||
|
return {
|
||||||
|
'COMPANY_NAME': os.environ.get('COMPANY_NAME', 'QR Code Management System')
|
||||||
|
}
|
||||||
|
|
||||||
def create_performance_indexes():
|
def create_performance_indexes():
|
||||||
"""Create performance optimization indexes"""
|
"""Create performance optimization indexes"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
+161
-24
@@ -4,31 +4,163 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Dashboard Header */
|
/* Dashboard Header */
|
||||||
.dashboard-header {
|
.header-stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
align-items: center;
|
||||||
align-items: flex-start;
|
}
|
||||||
margin-bottom: var(--spacing-8);
|
|
||||||
padding: var(--spacing-6);
|
.header-stats-grid {
|
||||||
background: var(--white);
|
display: grid;
|
||||||
border-radius: var(--radius-xl);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
box-shadow: var(--shadow);
|
gap: 1rem;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.header-stats-grid {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card {
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-header::before {
|
.header-stat-card::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 4px;
|
height: 2px;
|
||||||
background: linear-gradient(
|
}
|
||||||
90deg,
|
|
||||||
var(--primary-color),
|
.header-stat-card.primary::before {
|
||||||
var(--primary-hover)
|
background: linear-gradient(90deg, #2563eb, #1d4ed8);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
.header-stat-card.success::before {
|
||||||
|
background: linear-gradient(90deg, #10b981, #047857);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.danger::before {
|
||||||
|
background: linear-gradient(90deg, #ef4444, #dc2626);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.info::before {
|
||||||
|
background: linear-gradient(90deg, #8b5cf6, #7c3aed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #ffffff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.primary .header-stat-icon {
|
||||||
|
background: linear-gradient(135deg, #2563eb, #1d4ed8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.success .header-stat-icon {
|
||||||
|
background: linear-gradient(135deg, #10b981, #047857);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.danger .header-stat-icon {
|
||||||
|
background: linear-gradient(135deg, #ef4444, #dc2626);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card.info .header-stat-icon {
|
||||||
|
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-content h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0f172a;
|
||||||
|
margin-bottom: 0.125rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-content p {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update existing dashboard header to accommodate new layout */
|
||||||
|
.dashboard-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2rem;
|
||||||
|
background: linear-gradient(135deg, #a0aff1 0%, #ebdef8 100%);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design for Header */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.dashboard-header {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stats-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.dashboard-header {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stats-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-card {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-content h3 {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-stat-content p {
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome-section h1 {
|
.welcome-section h1 {
|
||||||
@@ -892,7 +1024,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.qr-url {
|
.qr-url {
|
||||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
||||||
background: var(--gray-100);
|
background: var(--gray-100);
|
||||||
padding: var(--spacing-1) var(--spacing-2);
|
padding: var(--spacing-1) var(--spacing-2);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
@@ -927,7 +1059,8 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-status, .qr-project {
|
.qr-status,
|
||||||
|
.qr-project {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-1);
|
gap: var(--spacing-1);
|
||||||
@@ -1088,8 +1221,12 @@
|
|||||||
|
|
||||||
/* Animations */
|
/* Animations */
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; }
|
from {
|
||||||
to { opacity: 1; }
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideIn {
|
@keyframes slideIn {
|
||||||
@@ -1108,26 +1245,26 @@
|
|||||||
.detail-grid {
|
.detail-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-actions {
|
.qr-actions {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr-actions .btn {
|
.qr-actions .btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk-actions-bar {
|
.bulk-actions-bar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bulk-actions-buttons {
|
.bulk-actions-buttons {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
margin: var(--spacing-4);
|
margin: var(--spacing-4);
|
||||||
max-width: calc(100vw - 2rem);
|
max-width: calc(100vw - 2rem);
|
||||||
|
|||||||
+6
-2
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{% block title %}QR Code Management System{% endblock %}</title>
|
<title>{% block title %}{{ COMPANY_NAME }}{% endblock %}</title>
|
||||||
|
|
||||||
<!-- Main CSS -->
|
<!-- Main CSS -->
|
||||||
<link
|
<link
|
||||||
@@ -87,7 +87,11 @@
|
|||||||
</script>
|
</script>
|
||||||
{% if turnstile_enabled %}
|
{% if turnstile_enabled %}
|
||||||
<!-- Cloudflare Turnstile -->
|
<!-- Cloudflare Turnstile -->
|
||||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
<script
|
||||||
|
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
|
||||||
|
async
|
||||||
|
defer
|
||||||
|
></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>{% block title %}QR Code Management System{% endblock %}</title>
|
<title>{% block title %}{{ COMPANY_NAME }}{% endblock %}</title>
|
||||||
|
|
||||||
<!-- Main CSS -->
|
<!-- Main CSS -->
|
||||||
<link
|
<link
|
||||||
@@ -55,8 +55,10 @@
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% if session.role == 'admin' %}
|
{% if session.role == 'admin' %}
|
||||||
<a href="{{ url_for('projects') }}"
|
<a
|
||||||
class="menu-item {% if request.endpoint in ['projects', 'create_project', 'edit_project'] %}active{% endif %}">
|
href="{{ url_for('projects') }}"
|
||||||
|
class="menu-item {% if request.endpoint in ['projects', 'create_project', 'edit_project'] %}active{% endif %}"
|
||||||
|
>
|
||||||
<i class="fas fa-folder"></i>
|
<i class="fas fa-folder"></i>
|
||||||
<span class="menu-text">Projects</span>
|
<span class="menu-text">Projects</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -65,8 +67,8 @@
|
|||||||
<span class="menu-text">Users</span>
|
<span class="menu-text">Users</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ url_for('employees') }}" class="menu-item">
|
<a href="{{ url_for('employees') }}" class="menu-item">
|
||||||
<i class="fas fa-user"></i>
|
<i class="fas fa-user"></i>
|
||||||
<span class="menu-text">Employees</span>
|
<span class="menu-text">Employees</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ url_for('attendance_report') }}" class="menu-item">
|
<a href="{{ url_for('attendance_report') }}" class="menu-item">
|
||||||
<i class="fas fa-chart-line"></i>
|
<i class="fas fa-chart-line"></i>
|
||||||
@@ -76,12 +78,17 @@
|
|||||||
<i class="fas fa-calculator"></i>
|
<i class="fas fa-calculator"></i>
|
||||||
<span class="menu-text">Payroll</span>
|
<span class="menu-text">Payroll</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ url_for('qr_statistics') }}" class="menu-item {% if request.endpoint == 'qr_statistics' %}active{% endif %}">
|
<a
|
||||||
|
href="{{ url_for('qr_statistics') }}"
|
||||||
|
class="menu-item {% if request.endpoint == 'qr_statistics' %}active{% endif %}"
|
||||||
|
>
|
||||||
<i class="fas fa-chart-pie"></i>
|
<i class="fas fa-chart-pie"></i>
|
||||||
<span class="menu-text">Statistics</span>
|
<span class="menu-text">Statistics</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ url_for('admin_logs') }}"
|
<a
|
||||||
class="menu-item {% if request.endpoint == 'admin_logs' %}active{% endif %}">
|
href="{{ url_for('admin_logs') }}"
|
||||||
|
class="menu-item {% if request.endpoint == 'admin_logs' %}active{% endif %}"
|
||||||
|
>
|
||||||
<i class="fas fa-clipboard-list"></i>
|
<i class="fas fa-clipboard-list"></i>
|
||||||
<span class="menu-text">System Logs</span>
|
<span class="menu-text">System Logs</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -137,9 +144,11 @@
|
|||||||
<span class="hamburger-line"></span>
|
<span class="hamburger-line"></span>
|
||||||
<span class="hamburger-line"></span>
|
<span class="hamburger-line"></span>
|
||||||
</button>
|
</button>
|
||||||
<h1 class="page-title">{% block page_title %}QR Code Management System{% endblock %}</h1>
|
<h1 class="page-title">
|
||||||
|
{% block page_title %}{{ COMPANY_NAME }}{% endblock %}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<span class="user-name">{{ session.full_name or 'User' }}</span>
|
<span class="user-name">{{ session.full_name or 'User' }}</span>
|
||||||
@@ -172,9 +181,7 @@
|
|||||||
{% endif %} {% endwith %}
|
{% endif %} {% endwith %}
|
||||||
|
|
||||||
<!-- Page Content -->
|
<!-- Page Content -->
|
||||||
<div class="container">
|
<div class="container">{% block content %}{% endblock %}</div>
|
||||||
{% block content %}{% endblock %}
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
@@ -210,4 +217,4 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+1484
-1362
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user