Update Branding look&feel.

This commit is contained in:
2025-07-06 17:16:19 +02:00
parent 462d91c3a8
commit 5b857a9a33

View File

@@ -1,30 +1,40 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% block content %} {% block content %}
<div class="container"> <div class="management-container">
<div class="header-section"> <div class="management-header">
<h1>🎨 System Administrator - Branding Settings</h1> <h1>🎨 Branding Settings</h1>
<p class="subtitle">Customize the appearance and branding of your TimeTrack instance</p> <div class="management-actions">
<a href="{{ url_for('system_admin_dashboard') }}" class="btn btn-secondary">← Back to Dashboard</a> <a href="{{ url_for('system_admin_dashboard') }}" class="btn btn-secondary">← Back to Dashboard</a>
</div>
</div> </div>
<p class="subtitle">Customize the appearance and branding of {{ branding.app_name }}</p>
<!-- Current Branding Preview --> <!-- Current Branding Preview -->
<div class="stats-section"> <div class="management-section">
<h3>👁️ Current Branding Preview</h3> <h2>👁️ Current Branding Preview</h2>
<div class="branding-preview"> <div class="management-card branding-preview-card">
<div class="preview-card"> <div class="card-header">
<div class="preview-header"> <h3>Live Preview</h3>
{% if branding.logo_filename %} </div>
<img src="{{ url_for('static', filename='uploads/branding/' + branding.logo_filename) }}" <div class="card-body">
alt="{{ branding.logo_alt_text }}" <div class="preview-demo">
class="preview-logo"> <div class="demo-header">
{% endif %} {% if branding.logo_filename %}
<h4>{{ branding.app_name }}</h4> <img src="{{ url_for('static', filename='uploads/branding/' + branding.logo_filename) }}"
</div> alt="{{ branding.logo_alt_text }}"
<div class="preview-content"> class="demo-logo">
<p>This is how your branding will appear to users.</p> {% else %}
<div class="preview-button" style="background-color: {{ branding.primary_color }};"> <span class="demo-text-logo">{{ branding.app_name }}</span>
Sample Button {% endif %}
</div>
<div class="demo-content">
<p>Welcome to {{ branding.app_name }}</p>
<button class="btn btn-primary" style="background-color: {{ branding.primary_color }}; border-color: {{ branding.primary_color }};">
Sample Button
</button>
<a href="#" style="color: {{ branding.primary_color }};">Sample Link</a>
</div> </div>
</div> </div>
</div> </div>
@@ -32,191 +42,270 @@
</div> </div>
<!-- Branding Settings Form --> <!-- Branding Settings Form -->
<div class="settings-section"> <div class="management-section">
<h3>🔧 Branding Configuration</h3> <h2>🔧 Branding Configuration</h2>
<form method="POST" enctype="multipart/form-data" class="settings-form"> <div class="management-card">
<!-- Application Name --> <form method="POST" enctype="multipart/form-data" class="settings-form">
<div class="setting-group"> <!-- Application Name -->
<div class="setting-header"> <div class="form-section">
<h4>Application Name</h4> <h3>📝 Basic Information</h3>
<p>The name that appears throughout the application</p> <div class="form-group">
</div> <label for="app_name">Application Name</label>
<div class="setting-control"> <input type="text" id="app_name" name="app_name"
<label for="app_name">Application Name:</label> value="{{ branding.app_name }}"
<input type="text" id="app_name" name="app_name" class="form-control"
value="{{ branding.app_name }}" placeholder="TimeTrack"
class="form-control" required>
placeholder="TimeTrack" <small class="form-text text-muted">
required> This name will appear in the title, navigation, and throughout the interface.
<small class="setting-description"> </small>
This name will appear in the title, navigation, and throughout the interface. </div>
</small>
</div>
</div>
<!-- Logo Upload --> <div class="form-group">
<div class="setting-group"> <label for="logo_alt_text">Logo Alternative Text</label>
<div class="setting-header"> <input type="text" id="logo_alt_text" name="logo_alt_text"
<h4>Logo Upload</h4> value="{{ branding.logo_alt_text }}"
<p>Upload a custom logo for your application</p> class="form-control"
placeholder="Company Logo">
<small class="form-text text-muted">
Text displayed when the logo cannot be loaded (accessibility).
</small>
</div>
</div> </div>
<div class="setting-control">
<label for="logo_file">Logo File:</label> <!-- Visual Assets -->
<input type="file" id="logo_file" name="logo_file" <div class="form-section">
accept="image/*" <h3>🖼️ Visual Assets</h3>
class="form-control"> <div class="form-row">
{% if branding.logo_filename %} <div class="form-group col-md-6">
<div class="current-file"> <label for="logo_file">Logo Image</label>
<strong>Current logo:</strong> <input type="file" id="logo_file" name="logo_file"
<img src="{{ url_for('static', filename='uploads/branding/' + branding.logo_filename) }}" accept="image/*"
alt="{{ branding.logo_alt_text }}" class="form-control-file">
class="current-logo"> {% if branding.logo_filename %}
<div class="current-asset">
<img src="{{ url_for('static', filename='uploads/branding/' + branding.logo_filename) }}"
alt="{{ branding.logo_alt_text }}"
class="current-logo">
<span class="asset-label">Current logo</span>
</div>
{% endif %}
<small class="form-text text-muted">
PNG, JPG, GIF, SVG. Recommended: 200x50px
</small>
</div> </div>
{% endif %}
<small class="setting-description">
Supported formats: PNG, JPG, GIF, SVG. Recommended size: 200x50px or similar aspect ratio.
</small>
</div>
</div>
<!-- Logo Alt Text --> <div class="form-group col-md-6">
<div class="setting-group"> <label for="favicon_file">Favicon</label>
<div class="setting-header"> <input type="file" id="favicon_file" name="favicon_file"
<h4>Logo Alt Text</h4> accept="image/*"
<p>Alternative text for the logo (accessibility)</p> class="form-control-file">
</div> {% if branding.favicon_filename %}
<div class="setting-control"> <div class="current-asset">
<label for="logo_alt_text">Alt Text:</label> <img src="{{ url_for('static', filename='uploads/branding/' + branding.favicon_filename) }}"
<input type="text" id="logo_alt_text" name="logo_alt_text" alt="Current favicon"
value="{{ branding.logo_alt_text }}" class="current-favicon">
class="form-control" <span class="asset-label">Current favicon</span>
placeholder="Company Logo"> </div>
<small class="setting-description"> {% endif %}
This text will be read by screen readers and shown when the logo cannot be displayed. <small class="form-text text-muted">
</small> ICO, PNG. Recommended: 16x16px or 32x32px
</div> </small>
</div>
<!-- Favicon Upload -->
<div class="setting-group">
<div class="setting-header">
<h4>Favicon Upload</h4>
<p>Upload a custom favicon (browser tab icon)</p>
</div>
<div class="setting-control">
<label for="favicon_file">Favicon File:</label>
<input type="file" id="favicon_file" name="favicon_file"
accept="image/*"
class="form-control">
{% if branding.favicon_filename %}
<div class="current-file">
<strong>Current favicon:</strong>
<img src="{{ url_for('static', filename='uploads/branding/' + branding.favicon_filename) }}"
alt="Current favicon"
class="current-favicon">
</div> </div>
{% endif %} </div>
<small class="setting-description">
Supported formats: ICO, PNG (16x16px or 32x32px recommended).
</small>
</div> </div>
</div>
<!-- Primary Color --> <!-- Theme Settings -->
<div class="setting-group"> <div class="form-section">
<div class="setting-header"> <h3>🎨 Theme Settings</h3>
<h4>Primary Color</h4> <div class="form-group">
<p>The primary color used throughout the application</p> <label for="primary_color">Primary Color</label>
<div class="color-picker-wrapper">
<input type="color" id="primary_color" name="primary_color"
value="{{ branding.primary_color }}"
class="form-control color-picker">
<input type="text" value="{{ branding.primary_color }}"
class="form-control color-value"
id="primary_color_text"
pattern="^#[0-9A-Fa-f]{6}$"
placeholder="#007bff">
</div>
<small class="form-text text-muted">
This color will be used for buttons, links, and other UI elements.
</small>
</div>
</div> </div>
<div class="setting-control">
<label for="primary_color">Primary Color:</label>
<input type="color" id="primary_color" name="primary_color"
value="{{ branding.primary_color }}"
class="form-control color-picker">
<small class="setting-description">
This color will be used for buttons, links, and other UI elements throughout the application.
</small>
</div>
</div>
<!-- Save Button --> <!-- Save Button -->
<div class="form-actions"> <div class="form-actions">
<button type="submit" class="btn btn-primary">💾 Save Branding Settings</button> <button type="submit" class="btn btn-primary">💾 Save Branding Settings</button>
</div> <a href="{{ url_for('system_admin_dashboard') }}" class="btn btn-secondary">Cancel</a>
</form> </div>
</form>
</div>
</div> </div>
</div> </div>
<style> <style>
/* Branding-specific styles that complement the existing design system */ /* Branding-specific styles */
.branding-preview { .branding-preview-card {
margin-bottom: 2rem;
}
.preview-demo {
background: #f8f9fa; background: #f8f9fa;
border: 1px solid #dee2e6; border-radius: 8px;
border-radius: 5px; padding: 2rem;
padding: 20px; text-align: center;
margin-top: 15px;
} }
.preview-card { .demo-header {
background: white; margin-bottom: 1.5rem;
border-radius: 5px; padding-bottom: 1rem;
padding: 20px; border-bottom: 1px solid #dee2e6;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
max-width: 400px;
} }
.preview-header { .demo-logo {
display: flex; max-height: 50px;
align-items: center; max-width: 200px;
gap: 15px;
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.preview-logo {
max-height: 40px;
max-width: 150px;
object-fit: contain; object-fit: contain;
} }
.preview-button { .demo-text-logo {
color: white; font-size: 1.5rem;
padding: 8px 16px; font-weight: 600;
border-radius: 4px; color: #333;
display: inline-block;
margin-top: 10px;
font-size: 14px;
border: none;
cursor: pointer;
} }
.current-file { .demo-content {
margin-top: 10px; margin-top: 1rem;
padding: 10px; }
.demo-content p {
color: #6c757d;
margin-bottom: 1rem;
}
.demo-content .btn {
margin-right: 1rem;
}
/* Current assets display */
.current-asset {
margin-top: 0.5rem;
padding: 0.75rem;
background: #f8f9fa; background: #f8f9fa;
border-radius: 4px; border-radius: 4px;
border: 1px solid #dee2e6; display: flex;
align-items: center;
gap: 1rem;
} }
.current-logo { .current-logo {
max-height: 30px; max-height: 40px;
max-width: 100px; max-width: 120px;
object-fit: contain; object-fit: contain;
margin-left: 10px;
} }
.current-favicon { .current-favicon {
max-height: 16px; width: 32px;
max-width: 16px; height: 32px;
object-fit: contain; object-fit: contain;
margin-left: 10px; }
.asset-label {
font-size: 0.875rem;
color: #6c757d;
}
/* Color picker styling */
.color-picker-wrapper {
display: flex;
gap: 0.5rem;
align-items: center;
max-width: 300px;
} }
.color-picker { .color-picker {
width: 80px !important; width: 60px;
height: 40px; height: 38px;
padding: 0 !important; padding: 0.25rem;
border: 1px solid #ced4da;
border-radius: 4px;
cursor: pointer;
} }
.color-value {
flex: 1;
font-family: monospace;
}
/* Form sections */
.form-section {
margin-bottom: 2rem;
padding-bottom: 2rem;
border-bottom: 1px solid #dee2e6;
}
.form-section:last-child {
border-bottom: none;
margin-bottom: 0;
}
.form-section h3 {
margin-bottom: 1rem;
color: #495057;
font-size: 1.1rem;
font-weight: 600;
}
/* File input styling */
.form-control-file {
display: block;
width: 100%;
padding: 0.375rem 0;
}
/* Form row for two-column layout */
.form-row {
display: flex;
flex-wrap: wrap;
margin-right: -0.5rem;
margin-left: -0.5rem;
}
.form-row > .col-md-6 {
flex: 0 0 50%;
max-width: 50%;
padding-right: 0.5rem;
padding-left: 0.5rem;
}
@media (max-width: 768px) {
.form-row > .col-md-6 {
flex: 0 0 100%;
max-width: 100%;
}
}
/* Sync color inputs */
</style> </style>
<script>
// Sync color picker with text input
document.addEventListener('DOMContentLoaded', function() {
const colorPicker = document.getElementById('primary_color');
const colorText = document.getElementById('primary_color_text');
colorPicker.addEventListener('input', function() {
colorText.value = this.value;
});
colorText.addEventListener('input', function() {
if (this.value.match(/^#[0-9A-Fa-f]{6}$/)) {
colorPicker.value = this.value;
}
});
});
</script>
{% endblock %} {% endblock %}