Redesigns profile edit page

main
Yasen Pramatarov 2025-11-19 22:28:15 +02:00
parent b90d8099c1
commit 5422d63d83
2 changed files with 217 additions and 109 deletions

View File

@ -1,95 +1,76 @@
<!-- user profile --> <!-- user profile -->
<div class="card text-center w-50 mx-auto"> <div class="tm-profile-card mx-auto">
<div class="tm-profile-header">
<div>
<p class="tm-profile-eyebrow">Account</p>
<h2 class="tm-profile-title">Profile of <?= htmlspecialchars($userDetails[0]['username']) ?></h2>
<p class="tm-profile-subtitle">Update your personal details, avatar, and access rights in one streamlined view.</p>
</div>
</div>
<p class="h4 card-header">Profile of <?= htmlspecialchars($userDetails[0]['username']) ?></p> <form method="POST" action="<?= htmlspecialchars($app_root) ?>?page=profile" enctype="multipart/form-data" class="tm-profile-form" novalidate>
<div class="card-body">
<form method="POST" action="<?= htmlspecialchars($app_root) ?>?page=profile" enctype="multipart/form-data">
<?php include CSRF_TOKEN_INCLUDE; ?> <?php include CSRF_TOKEN_INCLUDE; ?>
<div class="row"> <div class="row g-4 align-items-start">
<p class="border rounded bg-light mb-4"><small>edit the profile fields</small></p> <div class="col-lg-4">
<div class="col-md-4 avatar-container"> <div class="tm-profile-avatar card h-100">
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<img class="avatar-img" src="<?= htmlspecialchars($app_root) . htmlspecialchars($avatar) ?>" alt="avatar" /> <img class="avatar-img" src="<?= htmlspecialchars($app_root) . htmlspecialchars($avatar) ?>" alt="avatar" />
<div class="avatar-btn-container"> </div>
<div class="avatar-btn-group">
<label for="avatar-upload" class="avatar-btn avatar-btn-select btn btn-primary"> <label for="avatar-upload" class="btn btn-outline-primary w-100">
<i class="fas fa-folder" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="select new avatar"></i> <i class="fas fa-upload me-2"></i>Upload new
</label> </label>
<input type="file" id="avatar-upload" name="avatar_file" accept="image/*" style="display:none;"> <input type="file" id="avatar-upload" name="avatar_file" accept="image/*" style="display:none;">
<?php if ($default_avatar) { ?> <?php if ($default_avatar) { ?>
<button type="button" class="avatar-btn avatar-btn-remove btn btn-secondary" data-toggle="modal" data-target="#confirmDeleteModal" disabled> <button type="button" class="btn btn-outline-secondary w-100" data-toggle="modal" data-target="#confirmDeleteModal" disabled>
<?php } else { ?> <?php } else { ?>
<button type="button" class="avatar-btn avatar-btn-remove btn btn-danger" data-toggle="modal" data-target="#confirmDeleteModal"> <button type="button" class="btn btn-outline-danger w-100" data-toggle="modal" data-target="#confirmDeleteModal">
<?php } ?> <?php } ?>
<i class="fas fa-trash" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="remove current avatar"></i> <i class="fas fa-trash me-2"></i>Remove avatar
</button> </button>
</div> </div>
<p class="avatar-hint">PNG, JPG up to 500 KB.</p>
</div>
</div>
<div class="col-lg-8">
<div class="tm-profile-section">
<h3 class="tm-profile-section-title">Personal info</h3>
<div class="row g-3">
<div class="col-md-6">
<label for="name" class="form-label">Full name</label>
<input class="form-control" type="text" name="name" id="name" value="<?= htmlspecialchars($userDetails[0]['name'] ?? '') ?>" autofocus />
</div>
<div class="col-md-6">
<label for="email" class="form-label">Email address</label>
<input class="form-control" type="text" name="email" id="email" value="<?= htmlspecialchars($userDetails[0]['email'] ?? '') ?>" />
</div>
</div> </div>
</div> </div>
<div class="col-md-8"> <div class="tm-profile-section">
<!--div class="row mb-3"> <h3 class="tm-profile-section-title">Timezone</h3>
<div class="col-md-4 text-end"> <label for="timezone" class="form-label">Preferred timezone</label>
<label for="username" class="form-label"><small>username:</small></label> <select class="form-control" name="timezone" id="timezone">
<span class="text-danger" style="margin-right: -12px;">*</span>
</div>
<div class="col-md-8 text-start bg-light">
<input class="form-control" type="text" name="username" value="<?= htmlspecialchars($userDetails[0]['username']) ?>" required />
</div>
</div-->
<div class="row mb-3">
<div class="col-md-4 text-end">
<label for="name" class="form-label"><small>name:</small></label>
</div>
<div class="col-md-8 text-start bg-light">
<input class="form-control" type="text" name="name" value="<?= htmlspecialchars($userDetails[0]['name'] ?? '') ?>" autofocus />
</div>
</div>
<div class="row mb-3">
<div class="col-md-4 text-end">
<label for="email" class="form-label"><small>email:</small></label>
</div>
<div class="col-md-8 text-start bg-light">
<input class="form-control" type="text" name="email" value="<?= htmlspecialchars($userDetails[0]['email'] ?? '') ?>" />
</div>
</div>
<div class="row mb-3">
<div class="col-md-4 text-end">
<label for="timezone" class="form-label"><small>timezone:</small></label>
</div>
<div class="col-md-8 text-start bg-light">
<select class="form-control" name="timezone" id="timezone">
<?php foreach ($allTimezones as $timezone) { ?> <?php foreach ($allTimezones as $timezone) { ?>
<option value="<?= htmlspecialchars($timezone) ?>" <?= $timezone === $userTimezone ? 'selected' : '' ?>> <option value="<?= htmlspecialchars($timezone) ?>" <?= $timezone === $userTimezone ? 'selected' : '' ?>>
<?= htmlspecialchars($timezone) ?>&nbsp;&nbsp;(<?= htmlspecialchars(getUTCOffset($timezone)) ?>) <?= htmlspecialchars($timezone) ?>&nbsp;&nbsp;(<?= htmlspecialchars(getUTCOffset($timezone)) ?>)
</option> </option>
<?php } ?> <?php } ?>
</select> </select>
</div> </div>
</div>
<div class="row mb-3"> <div class="tm-profile-section">
<div class="col-md-4 text-end"> <h3 class="tm-profile-section-title">Bio</h3>
<label for="bio" class="form-label"><small>bio:</small></label> <textarea class="form-control" name="bio" rows="6" placeholder="Share something about yourself, your role, or preferences."><?= htmlspecialchars($userDetails[0]['bio'] ?? '') ?></textarea>
</div> </div>
<div class="col-md-8 text-start bg-light">
<textarea class="form-control" name="bio" rows="10"><?= htmlspecialchars($userDetails[0]['bio'] ?? '') ?></textarea>
</div>
</div>
<div class="row mb-3"> <div class="tm-profile-section">
<div class="col-md-4 text-end"> <h3 class="tm-profile-section-title">Rights</h3>
<label for="rights" class="form-label"><small>rights:</small></label> <p class="tm-profile-section-helper">Toggle the permissions that should be associated with this user.</p>
</div> <div class="tm-rights-grid">
<div class="col-md-8 text-start bg-light">
<?php foreach ($allRights as $right) { <?php foreach ($allRights as $right) {
// Check if the current right exists in $userRights
$isChecked = false; $isChecked = false;
foreach ($userRights as $userRight) { foreach ($userRights as $userRight) {
if ($userRight['right_id'] === $right['right_id']) { if ($userRight['right_id'] === $right['right_id']) {
@ -97,51 +78,45 @@
break; break;
} }
} ?> } ?>
<div class="form-check"> <div class="form-check tm-right-item">
<input class="form-check-input" type="checkbox" name="rights[]" value="<?= htmlspecialchars($right['right_id']) ?>" id="right_<?= htmlspecialchars($right['right_id']) ?>" <?= $isChecked ? 'checked' : '' ?> /> <input class="form-check-input" type="checkbox" name="rights[]" value="<?= htmlspecialchars($right['right_id']) ?>" id="right_<?= htmlspecialchars($right['right_id']) ?>" <?= $isChecked ? 'checked' : '' ?> />
<label class="form-check-label" for="right_<?= htmlspecialchars($right['right_id']) ?>"><?= htmlspecialchars($right['right_name']) ?></label> <label class="form-check-label" for="right_<?= htmlspecialchars($right['right_id']) ?>"><?= htmlspecialchars($right['right_name']) ?></label>
</div>
<?php } ?>
</div> </div>
<?php } ?>
</div> </div>
</div> </div>
<p> <div class="tm-profile-actions">
<a href="<?= htmlspecialchars($app_root) ?>?page=profile" class="btn btn-secondary">Cancel</a> <a href="<?= htmlspecialchars($app_root) ?>?page=profile" class="btn btn-light tm-contact-back">Cancel</a>
<input type="submit" class="btn btn-primary" value="Save" /> <button type="submit" class="btn btn-primary tm-contact-submit">Save changes</button>
</p> </div>
</div> </div>
</form> </div>
</form>
<!-- avatar removal modal confirmation --> <!-- avatar removal modal confirmation -->
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="confirmDeleteModalLabel" aria-hidden="true"> <div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="confirmDeleteModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="confirmDeleteModalLabel">Confirm Avatar Deletion</h5> <h5 class="modal-title" id="confirmDeleteModalLabel">Confirm Avatar Deletion</h5>
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body text-center">
<img class="avatar-img" src="<?= htmlspecialchars($app_root) . htmlspecialchars($avatar) ?>" alt="avatar" /> <img class="avatar-img" src="<?= htmlspecialchars($app_root) . htmlspecialchars($avatar) ?>" alt="avatar" />
<br /> <p class="mt-3 mb-0">Are you sure you want to delete your avatar?<br />This action cannot be undone.</p>
Are you sure you want to delete your avatar? </div>
<br /> <div class="modal-footer">
This action cannot be undone. <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div> <form id="remove-avatar-form" data-action="remove-avatar" method="POST" action="<?= htmlspecialchars($app_root) ?>?page=profile&action=remove&item=avatar">
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<form id="remove-avatar-form" data-action="remove-avatar" method="POST" action="<?= htmlspecialchars($app_root) ?>?page=profile&action=remove&item=avatar">
<?php include CSRF_TOKEN_INCLUDE; ?> <?php include CSRF_TOKEN_INCLUDE; ?>
<button type="button" class="btn btn-danger" id="confirm-delete">Delete Avatar</button> <button type="button" class="btn btn-danger" id="confirm-delete">Delete Avatar</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
<!-- /user profile --> <!-- /user profile -->

View File

@ -5,6 +5,139 @@ html, body {
padding: 0; padding: 0;
} }
/* Profile form */
.tm-profile-card {
max-width: 1100px;
margin: 2.5rem auto;
background: rgba(255, 255, 255, 0.97);
border-radius: 1.5rem;
box-shadow: 0 30px 70px rgba(15, 23, 42, 0.12);
padding: 2.75rem;
}
.tm-profile-header {
margin-bottom: 2rem;
}
.tm-profile-eyebrow {
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: #94a3b8;
margin-bottom: 0.4rem;
}
.tm-profile-title {
margin: 0;
font-size: 2.1rem;
color: #0f172a;
font-weight: 700;
}
.tm-profile-subtitle {
margin-top: 0.4rem;
color: #64748b;
font-size: 1rem;
}
.tm-profile-section {
border: 1px solid rgba(148, 163, 184, 0.25);
border-radius: 1.2rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
background: rgba(248, 250, 252, 0.7);
}
.tm-profile-section-title {
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: #94a3b8;
margin-bottom: 1rem;
}
.tm-profile-section-helper {
font-size: 0.85rem;
color: #64748b;
margin-bottom: 0.8rem;
}
.tm-profile-form .form-label {
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #475569;
}
.tm-profile-form .form-control {
border-radius: 0.85rem;
border: 1px solid rgba(148, 163, 184, 0.7);
padding: 0.85rem 1rem;
}
.tm-profile-form .form-control:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.25);
}
.tm-profile-avatar .avatar-wrapper {
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
.tm-profile-avatar .avatar-img {
width: 160px;
height: 160px;
border-radius: 50%;
object-fit: cover;
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.2);
}
.avatar-btn-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.avatar-hint {
margin-top: 0.75rem;
font-size: 0.8rem;
color: #94a3b8;
text-align: center;
}
.tm-rights-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.75rem;
}
.tm-right-item {
padding: 0.75rem 0.85rem;
border: 1px solid rgba(148, 163, 184, 0.3);
border-radius: 0.85rem;
background: white;
}
.tm-profile-actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
margin-top: 1.5rem;
}
@media (max-width: 768px) {
.tm-profile-card {
padding: 2rem 1.5rem;
}
.tm-profile-actions {
flex-direction: column;
align-items: stretch;
}
}
.dashboard-stats-row { .dashboard-stats-row {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
justify-content: center; justify-content: center;