Add cosmetic context processor and update templates for custom CSS

- Introduced a new `cosmetic_context` processor to provide custom CSS data to templates.
- Updated `settings.py` to include the new context processor.
- Modified multiple HTML templates to utilize the `cosmetic` variable for dynamic CSS styling.
- Enhanced user interface elements with improved styling and accessibility features, including ARIA labels for form controls.
This commit is contained in:
Master3395
2025-09-13 18:38:57 +02:00
parent 97fd4e055a
commit 0773d8d9a4
14 changed files with 253 additions and 92 deletions

View File

@@ -96,6 +96,7 @@ TEMPLATES = [
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'baseTemplate.context_processors.version_context',
'baseTemplate.context_processors.cosmetic_context',
],
},
},

View File

@@ -7,4 +7,20 @@ def version_context(request):
'CYBERPANEL_VERSION': VERSION,
'CYBERPANEL_BUILD': BUILD,
'CYBERPANEL_FULL_VERSION': f"{VERSION}.{BUILD}"
}
}
def cosmetic_context(request):
"""Add cosmetic data (custom CSS) to all templates"""
try:
from .models import CyberPanelCosmetic
cosmetic = CyberPanelCosmetic.objects.get(pk=1)
return {
'cosmetic': cosmetic
}
except:
from .models import CyberPanelCosmetic
cosmetic = CyberPanelCosmetic()
cosmetic.save()
return {
'cosmetic': cosmetic
}

View File

@@ -15,6 +15,11 @@
<link rel="stylesheet" type="text/css" href="{% static 'baseTemplate/assets/bootstrap/css/bootstrap.min.css' %}?v={{ CP_VERSION }}">
<link rel="stylesheet" type="text/css" href="{% static 'baseTemplate/bootstrap-toggle.min.css' %}?v={{ CP_VERSION }}">
<!-- Custom CSS -->
<style>
{{ cosmetic.MainDashboardCSS | safe }}
</style>
<!-- Core Scripts -->
<script src="{% static 'baseTemplate/angularjs.1.6.5.js' %}?v={{ CP_VERSION }}"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>

View File

@@ -242,6 +242,16 @@
margin-right: 0.5rem;
}
.password-hint {
color: var(--text-secondary, #64748b);
margin-top: 0.5rem;
display: block;
}
.action-section {
margin-top: 2rem;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@@ -324,7 +334,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Website" %}</label>
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control">
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control" aria-label="{% trans 'Select Website' %}">
<option value="">{% trans "Choose a website..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -345,7 +355,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Email Account" %}</label>
<select ng-model="selectedEmail" class="form-control">
<select ng-model="selectedEmail" class="form-control" aria-label="{% trans 'Select Email Account' %}">
<option value="">{% trans "Choose an email account..." %}</option>
<option ng-repeat="email in emails track by $index" value="{$ email.email $}">{$ email.email $}</option>
</select>
@@ -374,19 +384,19 @@
<label class="form-label">{% trans "Generated Password" %}</label>
<div class="input-group">
<input type="text" name="email" class="form-control"
ng-model="emailPassword" readonly>
ng-model="emailPassword" readonly aria-label="{% trans 'Generated Password' %}">
<button type="button" ng-click="usePassword()" class="btn-secondary">
<i class="fas fa-check"></i>
{% trans "Use This Password" %}
</button>
</div>
<small style="color: var(--text-secondary, #64748b); margin-top: 0.5rem; display: block;">
<small class="password-hint">
<i class="fas fa-info-circle"></i>
{% trans "Make sure to save this password in a secure location" %}
</small>
</div>
<div style="margin-top: 2rem;">
<div class="action-section">
<button type="button" ng-click="changePassword()" class="btn-primary">
<i class="fas fa-save"></i>
{% trans "Change Password" %}

View File

@@ -135,6 +135,7 @@
background: var(--bg-hover, #f8f9ff);
border: 1px solid var(--border-color, #e8e9ff);
border-radius: 8px;
min-width: -webkit-fill-available;
min-width: fit-content;
}
@@ -304,6 +305,16 @@
width: 100%;
background: var(--success-color, #10b981);
}
.password-hint {
color: var(--text-secondary, #64748b);
margin-top: 0.5rem;
display: block;
}
.action-section {
margin-top: 2rem;
}
</style>
<div class="modern-container" ng-controller="createEmailAccount">
@@ -320,7 +331,7 @@
<h2 class="card-title">
<i class="fas fa-user-plus"></i>
{% trans "New Email Account" %}
<a target="_blank" href="https://platform.cyberpersons.com/MailTester/MailTester?utm_source=from-cyberpanel-inside&utm_medium=from-cyberpanel-inside&utm_campaign=from-cyberpanel-inside&utm_id=from-cyberpanel-inside&utm_term=from-cyberpanel-inside"
<a target="_blank" rel="noopener" href="https://platform.cyberpersons.com/MailTester/MailTester?utm_source=from-cyberpanel-inside&utm_medium=from-cyberpanel-inside&utm_campaign=from-cyberpanel-inside&utm_id=from-cyberpanel-inside&utm_term=from-cyberpanel-inside"
class="test-email-link">
<i class="fas fa-vial"></i>
{% trans "Test Email Delivery" %}
@@ -346,7 +357,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Website" %}</label>
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control">
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control" aria-label="{% trans 'Select Website' %}">
<option value="">{% trans "Choose a website..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -397,19 +408,19 @@
<label class="form-label">{% trans "Generated Password" %}</label>
<div class="input-group">
<input type="text" name="email" class="form-control"
ng-model="emailPassword" readonly>
ng-model="emailPassword" readonly aria-label="{% trans 'Generated Password' %}">
<button type="button" ng-click="usePassword()" class="btn-secondary">
<i class="fas fa-check"></i>
{% trans "Use This Password" %}
</button>
</div>
<small style="color: var(--text-secondary, #64748b); margin-top: 0.5rem; display: block;">
<small class="password-hint">
<i class="fas fa-info-circle"></i>
{% trans "Make sure to save this password in a secure location" %}
</small>
</div>
<div style="margin-top: 2rem;">
<div class="action-section">
<button type="button" ng-click="createEmailAccount()" class="btn-primary">
<i class="fas fa-plus-circle"></i>
{% trans "Create Email Account" %}

View File

@@ -323,7 +323,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Website" %}</label>
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control">
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control" aria-label="{% trans 'Select Website' %}">
<option value="">{% trans "Choose a website..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -339,7 +339,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Email Account" %}</label>
<select ng-model="selectedEmail" class="form-control">
<select ng-model="selectedEmail" class="form-control" aria-label="{% trans 'Select Email Account' %}">
<option value="">{% trans "Choose an email account..." %}</option>
<option ng-repeat="email in emails track by $index" value="{$ email.email $}">{$ email.email $}</option>
</select>

View File

@@ -307,6 +307,50 @@
margin-right: 0.5rem;
}
.install-icon {
color: #5b5fcf;
}
.progress-title {
color: var(--text-primary, #1e293b);
font-size: 1.125rem;
font-weight: 600;
margin-bottom: 1rem;
}
.terminal-pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
.table-domain {
width: 20%;
}
.table-private-key {
width: 40%;
}
.table-public-key {
width: 40%;
}
.domain-badge {
padding: 0.5rem 1rem;
background: var(--accent-light, #e0e7ff);
color: #5b5fcf;
border-radius: 6px;
font-weight: 600;
display: inline-block;
}
.key-hint {
color: var(--text-secondary, #64748b);
margin-top: 0.5rem;
display: block;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@@ -359,7 +403,7 @@
<h1 class="page-title">
<i class="fas fa-shield-alt"></i>
{% trans "DKIM Manager" %}
<a target="_blank" href="https://cyberpanel.net/KnowledgeBase/home/dkim-set-up-and-configurations/" class="docs-link">
<a target="_blank" rel="noopener" href="https://cyberpanel.net/KnowledgeBase/home/dkim-set-up-and-configurations/" class="docs-link">
<i class="fas fa-book"></i>
{% trans "DKIM Docs" %}
</a>
@@ -378,7 +422,7 @@
</div>
<div class="card-body">
<div class="install-notice">
<i class="fas fa-exclamation-circle fa-3x mb-3" style="color: #5b5fcf;"></i>
<i class="fas fa-exclamation-circle fa-3x mb-3 install-icon"></i>
<h3>{% trans "OpenDKIM is not installed" %}</h3>
<p class="mb-3">{% trans "OpenDKIM is required to manage DKIM keys for your domains" %}</p>
<a href="" ng-click="installOpenDKIM()" class="install-link">
@@ -407,12 +451,12 @@
<!-- Installation Log -->
<div ng-hide="openDKIMInstallBox">
<h3 style="color: var(--text-primary, #1e293b); font-size: 1.125rem; font-weight: 600; margin-bottom: 1rem;">
<h3 class="progress-title">
<i class="fas fa-terminal"></i>
{% trans "Installation Progress" %}
</h3>
<div class="terminal-box">
<pre ng-bind="requestData" style="margin: 0; white-space: pre-wrap; word-wrap: break-word;"></pre>
<pre ng-bind="requestData" class="terminal-pre"></pre>
</div>
</div>
</div>
@@ -438,7 +482,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Website" %}</label>
<select ng-change="fetchKeys()" ng-model="domainName" class="form-control">
<select ng-change="fetchKeys()" ng-model="domainName" class="form-control" aria-label="{% trans 'Select Website' %}">
<option value="">{% trans "Choose a website..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -465,29 +509,29 @@
<table class="keys-table">
<thead>
<tr>
<th style="width: 20%;">{% trans "Domain" %}</th>
<th style="width: 40%;">{% trans "Private Key" %}</th>
<th style="width: 40%;">{% trans "Public Key" %}</th>
<th class="table-domain">{% trans "Domain" %}</th>
<th class="table-private-key">{% trans "Private Key" %}</th>
<th class="table-public-key">{% trans "Public Key" %}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span style="padding: 0.5rem 1rem; background: var(--accent-light, #e0e7ff); color: #5b5fcf; border-radius: 6px; font-weight: 600; display: inline-block;">
<span class="domain-badge">
<i class="fas fa-globe"></i>
<span ng-bind="domainName"></span>
</span>
</td>
<td>
<textarea ng-bind="privateKey" rows="10" class="key-textarea" readonly></textarea>
<small style="color: var(--text-secondary, #64748b); margin-top: 0.5rem; display: block;">
<textarea ng-bind="privateKey" rows="10" class="key-textarea" readonly aria-label="{% trans 'Private Key' %}"></textarea>
<small class="key-hint">
<i class="fas fa-lock"></i>
{% trans "Keep this private key secure" %}
</small>
</td>
<td>
<textarea ng-bind="publicKey" rows="10" class="key-textarea" readonly></textarea>
<small style="color: var(--text-secondary, #64748b); margin-top: 0.5rem; display: block;">
<textarea ng-bind="publicKey" rows="10" class="key-textarea" readonly aria-label="{% trans 'Public Key' %}"></textarea>
<small class="key-hint">
<i class="fas fa-info-circle"></i>
{% trans "Add this as a TXT record in your DNS" %}
</small>

View File

@@ -277,6 +277,40 @@
display: inline-block;
}
.warning-icon {
color: var(--warning-color, #ffa000);
}
.table-id {
width: 10%;
}
.table-source {
width: 35%;
}
.table-destination {
width: 40%;
}
.table-actions {
width: 15%;
text-align: center;
}
.email-icon {
color: var(--accent-color, #5b5fcf);
margin-right: 0.5rem;
}
.destination-text {
margin-left: 0.5rem;
}
.full-width-btn {
width: 100%;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@@ -329,7 +363,7 @@
<h1 class="page-title">
<i class="fas fa-share-square"></i>
{% trans "Setup Email Forwarding" %}
<a target="_blank" href="https://cyberpanel.net/KnowledgeBase/home/email-forwarding/" class="docs-link">
<a target="_blank" rel="noopener" href="https://cyberpanel.net/KnowledgeBase/home/email-forwarding/" class="docs-link">
<i class="fas fa-book"></i>
{% trans "Forwarding Docs" %}
</a>
@@ -348,7 +382,7 @@
<div class="card-body">
{% if not status %}
<div class="disabled-notice">
<i class="fas fa-exclamation-triangle fa-3x mb-3" style="color: var(--warning-color, #ffa000);"></i>
<i class="fas fa-exclamation-triangle fa-3x mb-3 warning-icon"></i>
<h3>{% trans "Postfix is disabled" %}</h3>
<p class="mb-3">{% trans "You need to enable Postfix to setup email forwarding" %}</p>
<a href="{% url 'managePostfix' %}" class="btn-primary">
@@ -363,7 +397,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Website" %}</label>
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control">
<select ng-change="showEmailDetails()" ng-model="emailDomain" class="form-control" aria-label="{% trans 'Select Website' %}">
<option value="">{% trans "Choose a website..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -379,7 +413,7 @@
<div class="col-md-8">
<div class="form-group">
<label class="form-label">{% trans "Select Email Account" %}</label>
<select ng-change="selectForwardingEmail()" ng-model="selectedEmail" class="form-control">
<select ng-change="selectForwardingEmail()" ng-model="selectedEmail" class="form-control" aria-label="{% trans 'Select Email Account' %}">
<option value="">{% trans "Choose an email account..." %}</option>
<option ng-repeat="email in emails track by $index" value="{$ email.email $}">{$ email.email $}</option>
</select>
@@ -387,7 +421,7 @@
<div class="form-group">
<label class="form-label">{% trans "Forwarding Options" %}</label>
<select ng-change="selectForwardingEmail()" ng-model="forwardingOption" class="form-control">
<select ng-change="selectForwardingEmail()" ng-model="forwardingOption" class="form-control" aria-label="{% trans 'Forwarding Options' %}">
<option value="Forward to email">{% trans "Forward to email" %}</option>
<option value="Pipe to program">{% trans "Pipe to program" %}</option>
</select>
@@ -402,21 +436,21 @@
<div class="col-md-4">
<div class="form-group mb-3">
<label class="form-label">{% trans "Source Email" %}</label>
<input placeholder="{% trans 'Source' %}" type="email" class="form-control" ng-model="selectedEmail" readonly>
<input placeholder="{% trans 'Source' %}" type="email" class="form-control" ng-model="selectedEmail" readonly aria-label="{% trans 'Source Email' %}">
</div>
</div>
<div class="col-md-4">
<div class="form-group mb-3">
<label class="form-label">{% trans "Destination" %} <span ng-show="forwardingOption == 'Pipe to program'">{% trans "(Path to program)" %}</span></label>
<input placeholder="{% trans 'Enter destination email or program path' %}" type="text" class="form-control" ng-model="destinationEmail" required>
<input placeholder="{% trans 'Enter destination email or program path' %}" type="text" class="form-control" ng-model="destinationEmail" required aria-label="{% trans 'Destination' %}">
</div>
</div>
<div class="col-md-4">
<div class="form-group mb-3">
<label class="form-label">&nbsp;</label>
<button type="button" ng-click="forwardEmail()" class="btn-primary" style="width: 100%;">
<button type="button" ng-click="forwardEmail()" class="btn-primary full-width-btn">
<i class="fas fa-plus-circle"></i>
{% trans "Add Forwarding" %}
</button>
@@ -427,17 +461,17 @@
<table class="forwarding-table">
<thead>
<tr>
<th style="width: 10%;">{% trans "ID" %}</th>
<th style="width: 35%;">{% trans "Source" %}</th>
<th style="width: 40%;">{% trans "Destination" %}</th>
<th style="width: 15%; text-align: center;">{% trans "Actions" %}</th>
<th class="table-id">{% trans "ID" %}</th>
<th class="table-source">{% trans "Source" %}</th>
<th class="table-destination">{% trans "Destination" %}</th>
<th class="table-actions">{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="record in records track by $index">
<td><strong ng-bind="record.id"></strong></td>
<td>
<i class="fas fa-envelope" style="color: var(--accent-color, #5b5fcf); margin-right: 0.5rem;"></i>
<i class="fas fa-envelope email-icon"></i>
<span ng-bind="record.source"></span>
</td>
<td>
@@ -447,9 +481,9 @@
<span class="option-badge" ng-hide="record.destination.indexOf('@') > -1">
<i class="fas fa-terminal"></i> Program
</span>
<span style="margin-left: 0.5rem;" ng-bind="record.destination"></span>
<span class="destination-text" ng-bind="record.destination"></span>
</td>
<td style="text-align: center;">
<td class="table-actions">
<button type="button" ng-click="deleteForwarding(record.source, record.destination)" class="btn-danger">
<i class="fas fa-trash"></i>
{% trans "Delete" %}

View File

@@ -164,11 +164,9 @@
}
/* Fix for Firefox on Windows */
@-moz-document url-prefix() {
select.form-control {
color: var(--text-dark, #2f3640) !important;
text-shadow: none;
}
select.form-control {
color: var(--text-dark, #2f3640) !important;
text-shadow: none;
}
/* Ensure selected option is always visible */
@@ -397,6 +395,30 @@
flex-wrap: wrap;
}
.email-icon {
color: var(--accent-color, #5b5fcf);
margin-right: 0.5rem;
}
.email-address {
font-size: 0.9375rem;
color: var(--text-primary, #1e293b);
}
.disk-usage-badge {
padding: 0.375rem 0.875rem;
background: var(--bg-gradient, #f0f1ff);
color: var(--accent-color, #5b5fcf);
border-radius: 4px;
font-weight: 600;
font-size: 0.875rem;
}
.email-to-delete {
color: var(--danger-color, #ef4444);
font-weight: 600;
}
/* Modern Modal Styles */
.modal-content {
border-radius: 12px;
@@ -593,7 +615,7 @@
<div class="col-md-6">
<div class="form-group">
<label class="form-label">{% trans "Select Domain" %}</label>
<select ng-change="populateCurrentRecords()" ng-model="selectedDomain" class="form-control">
<select ng-change="populateCurrentRecords()" ng-model="selectedDomain" class="form-control" aria-label="{% trans 'Select Domain' %}">
<option value="">{% trans "Choose a domain..." %}</option>
{% for items in websiteList %}
<option value="{{ items }}">{{ items }}</option>
@@ -613,7 +635,7 @@
<a href="https://community.cyberpanel.net/t/6-self-signed-ssl-error-on-outlook-thunderbird/207" target="_blank" rel="noopener" style="color: var(--danger-text, #991b1b); text-decoration: underline;">{% trans "Learn more" %}</a>
</div>
</div>
<button ng-hide="mailConfigured==1" ng-click='fixMailSSL()' class="btn-primary mb-4">
<button type="button" ng-hide="mailConfigured==1" ng-click='fixMailSSL()' class="btn-primary mb-4">
<i class="fas fa-wrench"></i>
{% trans "Fix SSL Now" %}
</button>
@@ -731,11 +753,11 @@
<tbody>
<tr ng-repeat="record in records track by $index">
<td>
<i class="fas fa-user-circle" style="color: var(--accent-color, #5b5fcf); margin-right: 0.5rem;"></i>
<strong style="font-size: 0.9375rem; color: var(--text-primary, #1e293b);" ng-bind="record.email"></strong>
<i class="fas fa-user-circle email-icon"></i>
<strong class="email-address" ng-bind="record.email"></strong>
</td>
<td>
<span style="padding: 0.375rem 0.875rem; background: var(--bg-gradient, #f0f1ff); color: var(--accent-color, #5b5fcf); border-radius: 4px; font-weight: 600; font-size: 0.875rem;">
<span class="disk-usage-badge">
{{ record.DiskUsage }}
</span>
</td>
@@ -767,7 +789,7 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Change Password
<img ng-hide="cyberpanelLoading" src="{% static 'images/loading.gif' %}">
<img ng-hide="cyberpanelLoading" src="{% static 'images/loading.gif' %}" alt="Loading...">
</h4>
</div>
<div class="modal-body">
@@ -775,7 +797,7 @@
<div ng-hide="installationDetailsForm" class="form-group">
<label class="col-sm-3 control-label">{% trans "Email" %}</label>
<div class="col-sm-6">
<input name="name" type="text" class="form-control" ng-model="email" readonly>
<input name="name" type="text" class="form-control" ng-model="email" readonly aria-label="Email address">
</div>
</div>
@@ -784,7 +806,7 @@
<div ng-hide="installationDetailsForm" class="form-group">
<label class="col-sm-3 control-label">{% trans "Password" %}</label>
<div class="col-sm-6">
<input type="password" class="form-control" ng-model="$parent.password">
<input type="password" class="form-control" ng-model="$parent.password" aria-label="Password">
</div>
</div>
</form>
@@ -837,7 +859,7 @@
<p style="margin: 0.5rem 0 0 0;">{% trans "This will permanently delete the email account and all associated data including emails, folders, and settings." %}</p>
</div>
</div>
<p><strong>{% trans "Email to delete:" %}</strong> <span style="color: var(--danger-color, #ef4444); font-weight: 600;">{$ emailToDelete $}</span></p>
<p><strong>{% trans "Email to delete:" %}</strong> <span class="email-to-delete">{$ emailToDelete $}</span></p>
<p>{% trans "Are you sure you want to continue?" %}</p>
</div>
<div class="modal-footer">

View File

@@ -208,6 +208,7 @@
color: var(--text-primary, #2f3640);
font-weight: 600;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
display: block;
margin-bottom: 4px;

View File

@@ -411,7 +411,7 @@
<div class="package-selector-card">
<div class="form-group">
<label class="form-label">{% trans "Select Package to Delete" %}</label>
<select ng-change="fetchPackageDetails()" ng-model="packageToBeDeleted" class="form-control">
<select ng-change="fetchPackageDetails()" ng-model="packageToBeDeleted" class="form-control" aria-label="{% trans 'Select Package to Delete' %}">
<option value="">-- {% trans "Select a package" %} --</option>
{% for items in packageList %}
<option>{{ items }}</option>

View File

@@ -139,6 +139,10 @@
color: var(--warning-dark);
}
.status-icon {
font-size: 8px;
}
/* Action buttons */
.action-buttons {
display: flex;
@@ -344,6 +348,7 @@
color: var(--text-primary);
font-weight: 600;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
display: block;
margin-bottom: 4px;
@@ -483,7 +488,7 @@
<td>{$ record.ftpAccounts $}</td>
<td>
<span class="status-badge" ng-class="{'enabled': record.allowFullDomain, 'disabled': !record.allowFullDomain}">
<i class="fas fa-circle" style="font-size: 8px;"></i>
<i class="fas fa-circle status-icon"></i>
<span ng-if="record.allowFullDomain">{% trans "Enabled" %}</span>
<span ng-if="!record.allowFullDomain">{% trans "Disabled" %}</span>
</span>
@@ -526,7 +531,7 @@
<form name="editPackageForm">
<div class="form-group">
<label class="form-label">{% trans "Package Name" %}</label>
<input type="text" class="form-control" ng-model="name" readonly>
<input type="text" class="form-control" ng-model="name" readonly aria-label="{% trans 'Package Name' %}">
</div>
<div class="form-section">
@@ -537,14 +542,14 @@
<div class="form-group">
<label class="form-label">{% trans "Domains" %}</label>
<input type="number" class="form-control" ng-model="allowedDomains" required>
<input type="number" class="form-control" ng-model="allowedDomains" required aria-label="{% trans 'Number of domains allowed' %}">
<div class="help-text">{% trans "Number of domains allowed (0 = Unlimited)" %}</div>
</div>
<div class="form-group">
<label class="form-label">{% trans "Disk Space" %}</label>
<div class="input-group">
<input type="number" class="form-control" ng-model="diskSpace" required>
<input type="number" class="form-control" ng-model="diskSpace" required aria-label="{% trans 'Disk space in MB' %}">
<span class="input-suffix">MB</span>
</div>
<div class="help-text">{% trans "Disk space in MB (0 = Unlimited)" %}</div>
@@ -553,7 +558,7 @@
<div class="form-group">
<label class="form-label">{% trans "Bandwidth" %}</label>
<div class="input-group">
<input type="number" class="form-control" ng-model="bandwidth" required>
<input type="number" class="form-control" ng-model="bandwidth" required aria-label="{% trans 'Monthly bandwidth in MB' %}">
<span class="input-suffix">MB</span>
</div>
<div class="help-text">{% trans "Monthly bandwidth in MB (0 = Unlimited)" %}</div>
@@ -568,17 +573,17 @@
<div class="form-group">
<label class="form-label">{% trans "Email Accounts" %}</label>
<input type="number" class="form-control" ng-model="emails" required>
<input type="number" class="form-control" ng-model="emails" required aria-label="{% trans 'Number of email accounts' %}">
</div>
<div class="form-group">
<label class="form-label">{% trans "Databases" %}</label>
<input type="number" class="form-control" ng-model="dataBases" required>
<input type="number" class="form-control" ng-model="dataBases" required aria-label="{% trans 'Number of databases' %}">
</div>
<div class="form-group">
<label class="form-label">{% trans "FTP Accounts" %}</label>
<input type="number" class="form-control" ng-model="ftpAccounts" required>
<input type="number" class="form-control" ng-model="ftpAccounts" required aria-label="{% trans 'Number of FTP accounts' %}">
</div>
</div>

View File

@@ -243,6 +243,7 @@
color: var(--text-primary, #2f3640);
font-weight: 600;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
display: block;
margin-bottom: 4px;
@@ -393,7 +394,7 @@
<div class="package-selector-card">
<div class="form-group">
<label class="form-label">{% trans "Select Package to Modify" %}</label>
<select ng-change="fetchDetails()" ng-model="packageToBeModified" class="form-control">
<select ng-change="fetchDetails()" ng-model="packageToBeModified" class="form-control" aria-label="{% trans 'Select Package to Modify' %}">
<option value="">-- {% trans "Select a package" %} --</option>
{% for items in packList %}
<option>{{ items }}</option>
@@ -417,7 +418,7 @@
<div class="form-group">
<label class="form-label">{% trans "Domains" %}</label>
<input type="number" class="form-control" ng-model="allowedDomains" required>
<input type="number" class="form-control" ng-model="allowedDomains" required aria-label="{% trans 'Number of domains allowed' %}">
<div class="help-text">{% trans "Number of domains allowed (0 = Unlimited)" %}</div>
</div>
@@ -425,7 +426,7 @@
<div class="form-group">
<label class="form-label">{% trans "Disk Space" %}</label>
<div class="input-group">
<input type="number" class="form-control" ng-model="diskSpace" required>
<input type="number" class="form-control" ng-model="diskSpace" required aria-label="{% trans 'Disk space in MB' %}">
<span class="input-suffix">MB</span>
</div>
<div class="help-text">{% trans "Disk space in MB (0 = Unlimited)" %}</div>
@@ -434,7 +435,7 @@
<div class="form-group">
<label class="form-label">{% trans "Bandwidth" %}</label>
<div class="input-group">
<input type="number" class="form-control" ng-model="bandwidth" required>
<input type="number" class="form-control" ng-model="bandwidth" required aria-label="{% trans 'Monthly bandwidth in MB' %}">
<span class="input-suffix">MB</span>
</div>
<div class="help-text">{% trans "Monthly bandwidth in MB (0 = Unlimited)" %}</div>
@@ -451,20 +452,20 @@
<div class="form-row">
<div class="form-group">
<label class="form-label">{% trans "FTP Accounts" %}</label>
<input type="number" class="form-control" ng-model="ftpAccounts" required>
<input type="number" class="form-control" ng-model="ftpAccounts" required aria-label="{% trans 'Number of FTP accounts' %}">
<div class="help-text">{% trans "Number of FTP accounts" %}</div>
</div>
<div class="form-group">
<label class="form-label">{% trans "Databases" %}</label>
<input type="number" class="form-control" ng-model="dataBases" required>
<input type="number" class="form-control" ng-model="dataBases" required aria-label="{% trans 'Number of MySQL databases' %}">
<div class="help-text">{% trans "Number of MySQL databases" %}</div>
</div>
</div>
<div class="form-group">
<label class="form-label">{% trans "Email Accounts" %}</label>
<input type="number" class="form-control" ng-model="emails" required>
<input type="number" class="form-control" ng-model="emails" required aria-label="{% trans 'Number of email accounts' %}">
<div class="help-text">{% trans "Number of email accounts" %}</div>
</div>
</div>

View File

@@ -182,6 +182,7 @@
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.2);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
border-radius: 12px;
display: flex;
@@ -190,6 +191,14 @@
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.package-icon i {
font-size: 1.75rem;
}
.loading-spinner-inline {
margin-left: 1rem;
}
.page-subtitle {
font-size: 1.125rem;
color: var(--text-on-gradient);
@@ -207,6 +216,7 @@
.stat-badge {
background: rgba(255, 255, 255, 0.2);
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
padding: 0.5rem 1.5rem;
border-radius: 20px;
@@ -560,6 +570,7 @@
align-items: center;
justify-content: center;
z-index: 1000;
-webkit-backdrop-filter: blur(4px);
backdrop-filter: blur(4px);
}
@@ -760,7 +771,7 @@
<div class="header-content">
<h1 class="page-title">
<div class="package-icon">
<i class="fas fa-cube" style="font-size: 1.75rem;"></i>
<i class="fas fa-cube"></i>
</div>
{% trans "System Package Manager" %}
</h1>
@@ -786,15 +797,15 @@
<div class="tabs-container">
<!-- Tab Navigation -->
<div class="modern-tabs">
<button class="tab-item active" ng-click="fetchPackages('upgrade')" data-tab="updates">
<button type="button" class="tab-item active" ng-click="fetchPackages('upgrade')" data-tab="updates" aria-label="{% trans 'View available updates' %}">
<i class="fas fa-sync-alt tab-icon"></i>
{% trans "Available Updates" %}
</button>
<button class="tab-item" ng-click="fetchPackages()" data-tab="all">
<button type="button" class="tab-item" ng-click="fetchPackages()" data-tab="all" aria-label="{% trans 'View all packages' %}">
<i class="fas fa-list tab-icon"></i>
{% trans "All Packages" %}
</button>
<button class="tab-item" ng-click="fetchPackages('CyberPanel')" data-tab="cyberpanel">
<button type="button" class="tab-item" ng-click="fetchPackages('CyberPanel')" data-tab="cyberpanel" aria-label="{% trans 'View CyberPanel packages' %}">
<i class="fas fa-shield-alt tab-icon"></i>
{% trans "CyberPanel Packages" %}
</button>
@@ -807,20 +818,20 @@
<div class="search-box">
<i class="fas fa-search search-icon"></i>
<input type="text" class="search-input" placeholder="{% trans 'Search packages...' %}"
ng-model="packSearch">
ng-model="packSearch" aria-label="{% trans 'Search packages' %}">
</div>
<div class="control-group">
<select ng-model="recordsToShow" class="select-control"
ng-change="fetchPackages(currentTab)">
ng-change="fetchPackages(currentTab)" aria-label="{% trans 'Records per page' %}">
<option value="10">10 {% trans "per page" %}</option>
<option value="50">50 {% trans "per page" %}</option>
<option value="100">100 {% trans "per page" %}</option>
<option value="500">500 {% trans "per page" %}</option>
</select>
<button class="btn btn-success" ng-click="updatePackage('all')"
ng-show="currentTab === 'upgrade'">
<button type="button" class="btn btn-success" ng-click="updatePackage('all')"
ng-show="currentTab === 'upgrade'" aria-label="{% trans 'Update all packages' %}">
<i class="fas fa-download"></i>
{% trans "Update All" %}
</button>
@@ -865,24 +876,24 @@
</span>
</td>
<td>
<a class="lock-toggle"
ng-class="{'locked': package.lock == 1, 'unlocked': package.lock == 0}"
ng-click="lockStatus(package.package, package.lock == 1 ? 1 : 0)"
title="{$ package.lock == 1 ? 'Package is locked' : 'Package is unlocked' $}">
<button type="button" class="lock-toggle"
ng-class="{'locked': package.lock == 1, 'unlocked': package.lock == 0}"
ng-click="lockStatus(package.package, package.lock == 1 ? 1 : 0)"
aria-label="{$ package.lock == 1 ? 'Unlock package' : 'Lock package' $}">
<i class="fas"
ng-class="{'fa-lock': package.lock == 1, 'fa-lock-open': package.lock == 0}"></i>
</a>
</button>
</td>
<td>
<div class="action-buttons">
<button class="btn btn-info btn-sm"
ng-click="showPackageDetails(package.package)">
<button type="button" class="btn btn-info btn-sm"
ng-click="showPackageDetails(package.package)" aria-label="{% trans 'View package details' %}">
<i class="fas fa-info-circle"></i>
{% trans "Details" %}
</button>
<button class="btn btn-primary btn-sm"
<button type="button" class="btn btn-primary btn-sm"
ng-click="showUpdateModal(package.package)"
ng-show="currentTab === 'upgrade' || currentTab === 'cyberpanel'">
ng-show="currentTab === 'upgrade' || currentTab === 'cyberpanel'" aria-label="{% trans 'Update package' %}">
<i class="fas fa-download"></i>
{% trans "Update" %}
</button>
@@ -912,7 +923,7 @@
<div class="pagination-controls">
<span>{% trans "Page:" %}</span>
<select ng-model="currentPage" class="page-select"
ng-change="fetchPackages(currentTab)">
ng-change="fetchPackages(currentTab)" aria-label="{% trans 'Select page' %}">
<option ng-repeat="page in pagination" value="{$ $index + 1 $}">
{$ $index + 1 $}
</option>
@@ -931,7 +942,7 @@
<i class="fas fa-info-circle"></i>
{% trans "Package Details:" %} {$ selectedPackage $}
</h3>
<button class="modal-close" ng-click="closeDetails()">
<button type="button" class="modal-close" ng-click="closeDetails()" aria-label="{% trans 'Close details modal' %}">
<i class="fas fa-times"></i>
</button>
</div>
@@ -948,9 +959,9 @@
<h3 class="modal-title">
<i class="fas fa-download"></i>
{% trans "Updating Package:" %} {$ updatingPackage $}
<span ng-hide="cyberpanelLoading" class="loading-spinner" style="margin-left: 1rem;"></span>
<span ng-hide="cyberpanelLoading" class="loading-spinner loading-spinner-inline"></span>
</h3>
<button class="modal-close" ng-click="closeUpdate()" ng-disabled="!updateComplete">
<button type="button" class="modal-close" ng-click="closeUpdate()" ng-disabled="!updateComplete" aria-label="{% trans 'Close update modal' %}">
<i class="fas fa-times"></i>
</button>
</div>