feat: add custom avatar functionality (#248)
Co-authored-by: Dante Bradshaw <plansuperior@gmail.com>
This commit is contained in:
parent
40bcf3485e
commit
1dbebd3918
39
endpoints/user/delete_avatar.php
Normal file
39
endpoints/user/delete_avatar.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
require_once '../../includes/connect_endpoint.php';
|
||||
|
||||
session_start();
|
||||
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
die(json_encode([
|
||||
"success" => false,
|
||||
"message" => translate('session_expired', $i18n)
|
||||
]));
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
if (isset($input['avatar'])) {
|
||||
$avatar = "images/uploads/logos/avatars/".$input['avatar'];
|
||||
$sql = "SELECT avatar FROM user";
|
||||
$stmt = $db->prepare($sql);
|
||||
$result = $stmt->execute();
|
||||
$userAvatar = $result->fetchArray(SQLITE3_ASSOC)['avatar'];
|
||||
|
||||
// Check if $avatar matches the avatar in the user table
|
||||
if ($avatar === $userAvatar) {
|
||||
echo json_encode(array("success" => false));
|
||||
} else {
|
||||
// The avatars do not match
|
||||
$filePath = "../../" . $avatar;
|
||||
if (file_exists($filePath)) {
|
||||
unlink($filePath);
|
||||
echo json_encode(array("success" => true, "message" => translate("success", $i18n)));
|
||||
} else {
|
||||
echo json_encode(array("success" => false, "message" => translate("error", $i18n)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo json_encode(array("success" => false, "message" => translate("error", $i18n)));
|
||||
}
|
||||
|
||||
?>
|
||||
@ -85,6 +85,95 @@
|
||||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||||
$mainCurrencyId = $row['main_currency'];
|
||||
|
||||
function sanitizeFilename($filename) {
|
||||
$filename = preg_replace("/[^a-zA-Z0-9\s]/", "", $filename);
|
||||
$filename = str_replace(" ", "-", $filename);
|
||||
$filename = str_replace(".", "", $filename);
|
||||
return $filename;
|
||||
}
|
||||
|
||||
function validateFileExtension($fileExtension) {
|
||||
$allowedExtensions = ['png', 'jpg', 'jpeg', 'gif', 'jtif', 'webp'];
|
||||
return in_array($fileExtension, $allowedExtensions);
|
||||
}
|
||||
|
||||
function resizeAndUploadAvatar($uploadedFile, $uploadDir, $name) {
|
||||
$targetWidth = 80;
|
||||
$targetHeight = 80;
|
||||
|
||||
$timestamp = time();
|
||||
$originalFileName = $uploadedFile['name'];
|
||||
$fileExtension = strtolower(pathinfo($originalFileName, PATHINFO_EXTENSION));
|
||||
$fileExtension = validateFileExtension($fileExtension) ? $fileExtension : 'png';
|
||||
$fileName = $timestamp . '-avatars-' . sanitizeFilename($name) . '.' . $fileExtension;
|
||||
$uploadFile = $uploadDir . $fileName;
|
||||
|
||||
if (move_uploaded_file($uploadedFile['tmp_name'], $uploadFile)) {
|
||||
$fileInfo = getimagesize($uploadFile);
|
||||
|
||||
if ($fileInfo !== false) {
|
||||
$width = $fileInfo[0];
|
||||
$height = $fileInfo[1];
|
||||
|
||||
// Load the image based on its format
|
||||
if ($fileExtension === 'png') {
|
||||
$image = imagecreatefrompng($uploadFile);
|
||||
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
|
||||
$image = imagecreatefromjpeg($uploadFile);
|
||||
} elseif ($fileExtension === 'gif') {
|
||||
$image = imagecreatefromgif($uploadFile);
|
||||
} elseif ($fileExtension === 'webp') {
|
||||
$image = imagecreatefromwebp($uploadFile);
|
||||
} else {
|
||||
// Handle other image formats as needed
|
||||
return "";
|
||||
}
|
||||
|
||||
// Enable alpha channel (transparency) for PNG images
|
||||
if ($fileExtension === 'png') {
|
||||
imagesavealpha($image, true);
|
||||
}
|
||||
|
||||
$newWidth = $width;
|
||||
$newHeight = $height;
|
||||
|
||||
if ($width > $targetWidth) {
|
||||
$newWidth = $targetWidth;
|
||||
$newHeight = ($targetWidth / $width) * $height;
|
||||
}
|
||||
|
||||
if ($newHeight > $targetHeight) {
|
||||
$newWidth = ($targetHeight / $newHeight) * $newWidth;
|
||||
$newHeight = $targetHeight;
|
||||
}
|
||||
|
||||
$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
|
||||
imagesavealpha($resizedImage, true);
|
||||
$transparency = imagecolorallocatealpha($resizedImage, 0, 0, 0, 127);
|
||||
imagefill($resizedImage, 0, 0, $transparency);
|
||||
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||
|
||||
if ($fileExtension === 'png') {
|
||||
imagepng($resizedImage, $uploadFile);
|
||||
} elseif ($fileExtension === 'jpg' || $fileExtension === 'jpeg') {
|
||||
imagejpeg($resizedImage, $uploadFile);
|
||||
} elseif ($fileExtension === 'gif') {
|
||||
imagegif($resizedImage, $uploadFile);
|
||||
} elseif ($fileExtension === 'webp') {
|
||||
imagewebp($resizedImage, $uploadFile);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
imagedestroy($image);
|
||||
imagedestroy($resizedImage);
|
||||
return "images/uploads/logos/avatars/".$fileName;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isset($_SESSION['username']) && isset($_POST['username']) && isset($_POST['email']) && isset($_POST['avatar'])) {
|
||||
$oldUsername = $_SESSION['username'];
|
||||
$username = validate($_POST['username']);
|
||||
@ -93,6 +182,22 @@
|
||||
$main_currency = $_POST['main_currency'];
|
||||
$language = $_POST['language'];
|
||||
|
||||
if (! empty($_FILES['profile_pic']["name"])) {
|
||||
$file = $_FILES['profile_pic'];
|
||||
|
||||
$fileType = mime_content_type($_FILES['profile_pic']['tmp_name']);
|
||||
if (strpos($fileType, 'image') === false) {
|
||||
$response = [
|
||||
"success" => false,
|
||||
"errorMessage" => translate('fill_all_fields', $i18n)
|
||||
];
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
$name = $file['name'];
|
||||
$avatar = resizeAndUploadAvatar($_FILES['profile_pic'], '../../images/uploads/logos/avatars/', $name);
|
||||
}
|
||||
|
||||
if (isset($_POST['password']) && $_POST['password'] != "") {
|
||||
$password = $_POST['password'];
|
||||
if (isset($_POST['confirm_password'])) {
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<nav>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn" onClick="toggleDropdown()">
|
||||
<img src="images/avatars/<?= $userData['avatar'] ?>.svg" alt="me" id="avatar">
|
||||
<img src="<?= $userData['avatar'] ?>" alt="me" id="avatar">
|
||||
<span id="user"><?= $username ?></span>
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Icons",
|
||||
'payment_icons' => "Zahlungsweisen Icons",
|
||||
// Settings page
|
||||
'upload_avatar' => "Avatar hochladen",
|
||||
'file_type_error' => "Dateityp nicht unterstützt",
|
||||
'user_details' => "Benutzerdetails",
|
||||
"household" => "Haushalt",
|
||||
"save_member" => "Mitglied speichern",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Εικονίδια",
|
||||
'payment_icons' => "Εικονίδια Payment",
|
||||
// Settings page
|
||||
'upload_avatar' => "μεταφόρτωση άβαταρ",
|
||||
'file_type_error' => "Το αρχείο πρέπει να είναι τύπου jpg, jpeg, png, webp ή gif",
|
||||
'user_details' => "Λεπτομέρειες χρήστη",
|
||||
"household" => "Νοικοκυριό",
|
||||
"save_member" => "Αποθήκευση μέλους",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Icons",
|
||||
'payment_icons' => "Payment Icons",
|
||||
// Settings page
|
||||
'upload_avatar' => "Upload Avatar",
|
||||
'file_type_error' => "The file type supplied is not supported.",
|
||||
'user_details' => "User Details",
|
||||
"household" => "Household",
|
||||
"save_member" => "Save Member",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Iconos",
|
||||
'payment_icons' => "Iconos de Pago",
|
||||
// Settings page
|
||||
'upload_avatar' => "Subir avatar",
|
||||
'file_type_error' => "El archivo debe ser una imagen en formato PNG, JPG, WEBP o SVG",
|
||||
'user_details' => "Detalles del Usuario",
|
||||
"household" => "Hogar",
|
||||
"save_member" => "Guardar Miembro",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Icônes",
|
||||
'payment_icons' => "Icônes de paiement",
|
||||
// Page de paramètres
|
||||
'upload_avatar' => "Télécharger un Avatar",
|
||||
'file_type_error' => "Le type de fichier n'est pas pris en charge",
|
||||
'user_details' => "Détails de l'utilisateur",
|
||||
"household" => "Ménage",
|
||||
"save_member" => "Enregistrer le membre",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "アイコン",
|
||||
'payment_icons' => "支払いアイコン",
|
||||
// Settings page
|
||||
'upload_avatar' => "アバターをアップロードする",
|
||||
'file_type_error' => "ファイルタイプが許可されていません",
|
||||
'user_details' => "ユーザー詳細",
|
||||
"household" => "世帯",
|
||||
"save_member" => "世帯員を保存",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "Ícones",
|
||||
'payment_icons' => "Ícones de Pagamentos",
|
||||
// Settings page
|
||||
'upload_avatar' => "Enviar avatar",
|
||||
'file_type_error' => "Tipo de ficheiro não permitido",
|
||||
'user_details' => "Detalhes do utilizador",
|
||||
"household" => "Agregado",
|
||||
"save_member" => "Guardar Membro",
|
||||
|
||||
@ -95,6 +95,8 @@ $i18n = [
|
||||
'icons' => "Ícones",
|
||||
'payment_icons' => "Ícones de pagamento",
|
||||
// Settings page
|
||||
'upload_avatar' => "Carregar avatar",
|
||||
'file_type_error' => "Tipo de arquivo não permitido",
|
||||
'user_details' => "Informações do Usuário",
|
||||
"household" => "Membros",
|
||||
"save_member" => "Salvar membro",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "İkonlar",
|
||||
'payment_icons' => "Ödeme İkonları",
|
||||
// Settings page
|
||||
'upload_avatar' => "Avatarı yükle",
|
||||
'file_type_error' => "Dosya türü izin verilmiyor",
|
||||
'user_details' => "Kullanıcı Detayları",
|
||||
"household" => "Hane",
|
||||
"save_member" => "Üyeyi Kaydet",
|
||||
|
||||
@ -104,6 +104,8 @@ $i18n = [
|
||||
'payment_icons' => "支付图标",
|
||||
|
||||
// 设置页面
|
||||
'upload_avatar' => "上传头像",
|
||||
'file_type_error' => "文件类型不允许",
|
||||
'user_details' => "用户详情",
|
||||
"household" => "家庭",
|
||||
"save_member" => "保存成员",
|
||||
|
||||
@ -97,6 +97,8 @@ $i18n = [
|
||||
'icons' => "圖示",
|
||||
'payment_icons' => "付款圖示",
|
||||
// 設定頁面
|
||||
'upload_avatar' => "上传头像",
|
||||
'file_type_error' => "文件类型不允许",
|
||||
'user_details' => "使用者詳細資訊",
|
||||
"household" => "家庭",
|
||||
"save_member" => "儲存成員",
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
$version = "v1.17.3";
|
||||
$version = "v1.18.0";
|
||||
?>
|
||||
25
migrations/000013.php
Normal file
25
migrations/000013.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This migration script updates the avatar field of the user table to use the new avatar path.
|
||||
*/
|
||||
|
||||
/** @noinspection PhpUndefinedVariableInspection */
|
||||
$sql = "SELECT avatar FROM user";
|
||||
$stmt = $db->prepare($sql);
|
||||
$result = $stmt->execute();
|
||||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||||
|
||||
if ($row) {
|
||||
$avatar = $row['avatar'];
|
||||
|
||||
if (strlen($avatar) < 2) {
|
||||
$avatarFullPath = "images/avatars/" . $avatar . ".svg";
|
||||
$sql = "UPDATE user SET avatar = :avatarFullPath";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->bindValue(':avatarFullPath', $avatarFullPath, SQLITE3_TEXT);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -43,7 +43,7 @@ if (isset($_POST['username'])) {
|
||||
$confirm_password = $_POST['confirm_password'];
|
||||
$main_currency = $_POST['main_currency'];
|
||||
$language = $_POST['language'];
|
||||
$avatar = "0";
|
||||
$avatar = "images/avatars/0.svg";
|
||||
|
||||
if ($password != $confirm_password) {
|
||||
$passwordMismatch = true;
|
||||
|
||||
@ -12,10 +12,61 @@ function closeAvatarSelect() {
|
||||
avatarSelect.classList.remove("is-open");
|
||||
}
|
||||
|
||||
function changeAvatar(number) {
|
||||
document.getElementById("avatarImg").src = "images/avatars/" + number + ".svg";
|
||||
document.getElementById("avatarUser").value = number;
|
||||
closeAvatarSelect();
|
||||
document.querySelectorAll('.avatar-option').forEach((avatar) => {
|
||||
avatar.addEventListener("click", () => {
|
||||
changeAvatar(avatar.src);
|
||||
document.getElementById('avatarUser').value = avatar.getAttribute('data-src');
|
||||
closeAvatarSelect();
|
||||
})
|
||||
});
|
||||
|
||||
function changeAvatar(src) {
|
||||
document.getElementById("avatarImg").src = src;
|
||||
}
|
||||
|
||||
function successfulUpload(field, msg) {
|
||||
var reader = new FileReader();
|
||||
|
||||
if (field.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! ['image/jpeg', 'image/png', 'image/gif', 'image/jtif', 'image/webp'].includes(field.files[0]['type'])) {
|
||||
showErrorMessage(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
reader.onload = function() {
|
||||
changeAvatar(reader.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(field.files[0]);
|
||||
closeAvatarSelect();
|
||||
}
|
||||
|
||||
function deleteAvatar(path) {
|
||||
fetch('/endpoints/user/delete_avatar.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ avatar: path }),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
var avatarContainer = document.querySelector(`.avatar-container[data-src="${path}"]`);
|
||||
if (avatarContainer) {
|
||||
avatarContainer.remove();
|
||||
}
|
||||
showSuccessMessage();
|
||||
} else {
|
||||
showErrorMessage();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function addMemberButton(memberId) {
|
||||
@ -681,7 +732,6 @@ function deletePaymentMethod(paymentId) {
|
||||
}
|
||||
|
||||
function savePaymentMethodsSorting() {
|
||||
console.log("should save");
|
||||
const paymentMethods = document.getElementById('payments-list');
|
||||
const paymentMethodIds = Array.from(paymentMethods.children).map(paymentMethod => paymentMethod.dataset.paymentid);
|
||||
|
||||
@ -733,8 +783,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
var newAvatar = document.getElementById("avatarUser").value;
|
||||
document.getElementById("avatar").src = "images/avatars/" + newAvatar + ".svg";
|
||||
document.getElementById("avatar").src = document.getElementById("avatarImg").src;
|
||||
var newUsername = document.getElementById("username").value;
|
||||
document.getElementById("user").textContent = newUsername;
|
||||
showSuccessMessage(data.message);
|
||||
|
||||
33
settings.php
33
settings.php
@ -13,12 +13,12 @@
|
||||
<header>
|
||||
<h2><?= translate('user_details', $i18n) ?></h2>
|
||||
</header>
|
||||
<form action="endpoints/user/saveuser.php" method="post" id="userForm">
|
||||
<form action="endpoints/user/saveuser.php" method="post" id="userForm" enctype="multipart/form-data">
|
||||
<div class="user-form">
|
||||
<div class="fields">
|
||||
<div>
|
||||
<div class="user-avatar">
|
||||
<img src="images/avatars/<?= $userData['avatar'] ?>.svg" alt="avatar" class="avatar" id="avatarImg" onClick="toggleAvatarSelect()"/>
|
||||
<img src="<?= $userData['avatar'] ?>" alt="avatar" class="avatar" id="avatarImg" onClick="toggleAvatarSelect()"/>
|
||||
<span class="edit-avatar" onClick="toggleAvatarSelect()">
|
||||
<img src="images/siteicons/editavatar.png" title="Change avatar" />
|
||||
</span>
|
||||
@ -27,17 +27,26 @@
|
||||
<input type="hidden" name="avatar" value="<?= $userData['avatar'] ?>" id="avatarUser"/>
|
||||
<div class="avatar-select" id="avatarSelect">
|
||||
<div class="avatar-list">
|
||||
<img src="images/avatars/0.svg" onClick="changeAvatar(0)" />
|
||||
<img src="images/avatars/1.svg" onClick="changeAvatar(1)" />
|
||||
<img src="images/avatars/2.svg" onClick="changeAvatar(2)" />
|
||||
<img src="images/avatars/3.svg" onClick="changeAvatar(3)" />
|
||||
<img src="images/avatars/4.svg" onClick="changeAvatar(4)" />
|
||||
<img src="images/avatars/5.svg" onClick="changeAvatar(5)" />
|
||||
<img src="images/avatars/6.svg" onClick="changeAvatar(6)" />
|
||||
<img src="images/avatars/7.svg" onClick="changeAvatar(7)" />
|
||||
<img src="images/avatars/8.svg" onClick="changeAvatar(8)" />
|
||||
<img src="images/avatars/9.svg" onClick="changeAvatar(9)" />
|
||||
<?php foreach (scandir('images/avatars') as $index => $image) :?>
|
||||
<?php if (! str_starts_with($image, '.')) :?>
|
||||
<img src="images/avatars/<?=$image?>" alt="<?=$image?>" class="avatar-option" data-src="images/avatars/<?=$image?>"/>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
<?php foreach (scandir('images/uploads/logos/avatars') as $index => $image) :?>
|
||||
<?php if (! str_starts_with($image, '.')) :?>
|
||||
<div class="avatar-container" data-src="<?=$image?>">
|
||||
<img src="images/uploads/logos/avatars/<?=$image?>" alt="<?=$image?>" class="avatar-option" data-src="images/uploads/logos/avatars/<?=$image?>"/>
|
||||
<div class="remove-avatar" onclick="deleteAvatar('<?=$image?>')" title="Delete avatar">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
<label for="profile_pic" class="add-avatar" title="<?= translate('upload_avatar', $i18n) ?>">
|
||||
<i class="fa-solid fa-arrow-up-from-bracket"></i>
|
||||
</label>
|
||||
</div>
|
||||
<input type="file" id="profile_pic"class="hidden-input" name="profile_pic" accept="image/jpeg, image/png, image/gif, image/webp" onChange="successfulUpload(this, '<?= translate('file_type_error', $i18n) ?>')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grow">
|
||||
|
||||
@ -21,6 +21,8 @@ sleep 1
|
||||
chmod -R 755 /var/www/html/db/
|
||||
chown -R www-data:www-data /var/www/html/db/
|
||||
|
||||
mkdir -p /var/www/html/images/uploads/logos/avatars
|
||||
|
||||
# Change permissions on the logos directory
|
||||
chmod -R 755 /var/www/html/images/uploads/logos
|
||||
chown -R www-data:www-data /var/www/html/images/uploads/logos
|
||||
|
||||
@ -85,6 +85,24 @@ input[type="button"].secondary-button:hover {
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list .remove-avatar {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list > img,
|
||||
.avatar-select .avatar-list .avatar-container > img {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list > img:hover,
|
||||
.avatar-select .avatar-list .avatar-container > img:hover {
|
||||
border: 1px solid #EEE;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list .remove-avatar:hover {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.toast {
|
||||
border: 1px solid #333;
|
||||
background: #222;
|
||||
|
||||
@ -103,7 +103,8 @@ header .logo .logo-image {
|
||||
|
||||
.dropbtn > img {
|
||||
width: 30px;
|
||||
height: 30 px;
|
||||
height: 30px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
@ -493,12 +494,23 @@ main > .contain {
|
||||
}
|
||||
}
|
||||
|
||||
header #avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.user-form .user-avatar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.user-form .user-avatar > img {
|
||||
cursor: pointer;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
max-width: 80px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.user-form .user-avatar .edit-avatar {
|
||||
@ -536,12 +548,16 @@ main > .contain {
|
||||
position: absolute;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
width: 300px;
|
||||
width: 336px;
|
||||
max-width: 100%;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.avatar-option {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.avatar-select {
|
||||
left: 50%;
|
||||
@ -555,14 +571,70 @@ main > .contain {
|
||||
|
||||
.avatar-select .avatar-list {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
gap: 18px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list > img {
|
||||
width: 40px;
|
||||
.avatar-select .avatar-list > img,
|
||||
.avatar-select .avatar-list .avatar-container > img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: contain;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list > img:hover,
|
||||
.avatar-select .avatar-list .avatar-container > img:hover {
|
||||
border: 1px solid #222;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list .avatar-container {
|
||||
position: relative;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.avatar-select label.add-avatar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px solid #007bff;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
margin: 0px;
|
||||
box-sizing: border-box;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.avatar-select label.add-avatar:hover {
|
||||
border-color: #8FBFFA;
|
||||
color: #8FBFFA;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list .remove-avatar {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -11px;
|
||||
background-color: #FFF;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #ccc;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
box-sizing: border-box;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.avatar-select .avatar-list .remove-avatar:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.user-form .fields .grow {
|
||||
@ -797,7 +869,8 @@ input[type="text"].short {
|
||||
}
|
||||
|
||||
input[type="submit"],
|
||||
input[type="button"] {
|
||||
input[type="button"],
|
||||
button.button {
|
||||
padding: 12px 30px;
|
||||
font-size: 16px;
|
||||
background-color: #007bff;
|
||||
@ -809,12 +882,14 @@ input[type="button"] {
|
||||
border: 2px solid #007bff;
|
||||
}
|
||||
|
||||
input[type="button"].secondary-button {
|
||||
input[type="button"].secondary-button,
|
||||
button.button.secondary-button {
|
||||
background-color: #FFFFFF;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
input[type="button"].secondary-button:hover {
|
||||
input[type="button"].secondary-button:hover,
|
||||
button.button.secondary-button:hover {
|
||||
background-color: #EEEEEE;
|
||||
color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
@ -836,12 +911,14 @@ input[type="submit"]:hover {
|
||||
}
|
||||
|
||||
input[type="submit"]:disabled,
|
||||
input[type="button"]:disabled {
|
||||
input[type="button"]:disabled,
|
||||
button.button:disabled {
|
||||
background-color: #ccc;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
input[type="button"].left {
|
||||
input[type="button"].left
|
||||
button.button.left {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user