изменение аватарки, выбор зоны картинки, фулл рабочее

This commit is contained in:
uniknow 2024-06-17 22:09:40 +04:00
parent f8fa0a4f72
commit a2fd7f7318
10 changed files with 386 additions and 75 deletions

6
package-lock.json generated
View file

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@sveltestrap/sveltestrap": "^6.2.4", "@sveltestrap/sveltestrap": "^6.2.4",
"@themesberg/flowbite": "^1.3.0", "@themesberg/flowbite": "^1.3.0",
"cropperjs": "^1.6.2",
"sass": "^1.70.0", "sass": "^1.70.0",
"socket.io": "^4.7.5", "socket.io": "^4.7.5",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",
@ -1553,6 +1554,11 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/cropperjs": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.6.2.tgz",
"integrity": "sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA=="
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",

View file

@ -36,6 +36,7 @@
"dependencies": { "dependencies": {
"@sveltestrap/sveltestrap": "^6.2.4", "@sveltestrap/sveltestrap": "^6.2.4",
"@themesberg/flowbite": "^1.3.0", "@themesberg/flowbite": "^1.3.0",
"cropperjs": "^1.6.2",
"sass": "^1.70.0", "sass": "^1.70.0",
"socket.io": "^4.7.5", "socket.io": "^4.7.5",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",

View file

@ -14,6 +14,19 @@
<style lang="scss"> <style lang="scss">
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, var(--blue), var(--purple));
background-repeat: no-repeat;
background-attachment: fixed;
border-radius: 15px;
}
::-webkit-scrollbar {
width: 3px;
}
@font-face { @font-face {
font-family: 'Comfortaa'; font-family: 'Comfortaa';
src: url('./fonts/Comfortaa-VariableFont_wght.ttf') format('truetype'); src: url('./fonts/Comfortaa-VariableFont_wght.ttf') format('truetype');

View file

@ -169,8 +169,8 @@
}); });
if (response.ok) { if (response.ok) {
let jopa = await response.json(); let data = await response.json();
return jopa.image_url return data.image_url
} else { } else {
console.log(response); console.log(response);
} }

View file

@ -1,6 +1,6 @@
export async function getAvatarHistory(token){ export async function getAvatarHistory(token){
let response = fetch(`https://docs.black-phoenix.ru/api/users/avatars`,{ let response = await fetch(`https://docs.black-phoenix.ru/api/users/avatars`,{
method: 'GET', method: 'GET',
credentials:'include', credentials:'include',
headers: {'Authorization': token }, headers: {'Authorization': token },
@ -8,9 +8,53 @@ export async function getAvatarHistory(token){
if(response.ok){ if(response.ok){
let data = await response.json(); let data = await response.json();
data = data.user_avatars
data.reverse();
return data; return data;
} }
else{ else{
console.log(response) console.log(response)
} }
} }
export async function getConfirmationCode(token, email){
console.log(token, email, "<-- лох")
const response = await fetch(`https://docs.black-phoenix.ru/api/users/send_confirmation_code`,{
method: 'POST',
credentials:'include',
headers: {'Content-Type': 'application/json',
'Authorization': token},
body: JSON.stringify({'email': email})
})
if(response.ok){
return true
}
else{
console.log(response)
}
}
export async function changeUserData(token, username, email, password, avatar, code){
let response = await fetch(`https://docs.black-phoenix.ru/api/users/change_data`,{
method: 'POST',
credentials:'include',
headers: {'Content-Type': 'application/json',
'Authorization': token },
body: JSON.stringify({"verification_code": code,
"email": email,
"username": username,
"new_password": password,
"avatar_url": avatar})
})
if(response.ok){
return true
}
else{
console.log(response)
}
}

View file

@ -5,17 +5,15 @@ export async function UserCheck(){
method: 'GET', method: 'GET',
credentials:'include', credentials:'include',
headers: {'Authorization': token }, headers: {'Authorization': token },
}) })
if(!response.ok){ if(response.ok){
console.log(response) const data = await response.json();
return(response.status) return data
} }
else{ else{
const data = await response.json(); console.log(response)
return data
} }
} }

View file

@ -110,7 +110,7 @@
width: 75px; width: 75px;
height: 75px; height: 75px;
border-radius: 50%; border-radius: 15px;
} }
.dropdown > * { .dropdown > * {

View file

@ -1,64 +1,153 @@
<script> <script>
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import { uploadImages } from '$lib/chat';
import { blur } from 'svelte/transition'; import { blur } from 'svelte/transition';
import Header from './../Header.svelte'; import Header from './../Header.svelte';
import { UserCheck } from '$lib/userFunction'; import { UserCheck } from '$lib/userFunction';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { getAvatarHistory } from '$lib/settings' import { getAvatarHistory, changeUserData, getConfirmationCode } from '$lib/settings'
let userName let token
let userEmail let confCode
let newAvatarVisualize let userData = []
let avatarHistory let oldName
let oldEmail
let afterChanging
let newAvatarVisualize = ""
let avatars = []
let newName = "" let newName = ""
let newEmail = "" let newEmail = ""
let newPassword = "" let newPassword = ""
let newAvatar = "" let newAvatar = ""
let code = ""
let showSubmitFiled = false let showSubmitDiv = false
onMount(async () => { onMount(async () => {
let token = localStorage.getItem('BPChat') token = localStorage.getItem('BPChat')
let userData = await UserCheck() userData = await UserCheck()
//console.log(userData) //console.log(userData)
avatarHistory = await getAvatarHistory(token) avatars = await getAvatarHistory(token)
console.log(avatarHistory) console.log(avatars)
userName = userData.username oldName = userData.username
userEmail = userData.email oldEmail = userData.email
console.log(`история аватарок ${avatarHistory}`) console.log(oldEmail)
}) })
function handleFileChange(event) { async function changingData(){
if(newName == "")
newName = oldName; console.log(newName, "новое имя")
if(newEmail == "")
newEmail = oldEmail; console.log(newEmail, "новая почта")
if(newPassword == "")
newPassword = null; console.log(newPassword, " новый пароль")
if(newAvatar == "")
newAvatar = null; console.log(newAvatar, "ава")
console.log(newName, newEmail, newPassword, newAvatar, " - измененные данные")
confCode = await getConfirmationCode(token, oldEmail)
if(confCode == true)
showSubmitDiv = true
else
console.log("ну ты лошара, земля тебе пухом")
}
async function submit(){
newAvatar = await uploadImages(newAvatar)
console.log(newAvatar)
let changing = afterChanging = await changeUserData(token, newName, newEmail, newPassword, newAvatar, code)
console.log(changing)
if (changing == true){
showSubmitDiv = false
location.reload()
}
}
function cancel(){
newName = ""
newEmail = ""
newPassword = ""
newAvatar = ""
newAvatarVisualize = ""
}
let imageElement;
let cropper;
let croppedImage = "";
let showCroppingImgDiv = false
const handleFileChange = (event) => {
showCroppingImgDiv = true
const file = event.target.files[0]; const file = event.target.files[0];
newAvatar = file
if (file) { if (file) {
const reader = new FileReader(); const reader = new FileReader();
reader.onloadend = (e) => { reader.onload = (e) => {
imageElement.src = e.target.result;
newAvatarVisualize = e.target.result; if (cropper) {
cropper.destroy();
}
cropper = new Cropper(imageElement, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0, // Начальное значение для автообрезки 0
center: true,
zoomOnTouch: false,
zoomOnWheel: false,
cropBoxMovable: true,
cropBoxResizable: true,
background: false, // Убирает сеточный фон
autoCrop: false, // Изначально не показывать зону обрезки
ready: function () {
cropper.setCropBoxData({
width: 200,
height: 200,
left: (cropper.getContainerData().width - 200) / 2,
top: (cropper.getContainerData().height - 200) / 2,
});
cropper.crop(); // Включить зону обрезки
},
});
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
} };
async function changingData(){ const getCroppedImage = () => {
showSubmitFiled = true if (cropper) {
} croppedImage = cropper.getCroppedCanvas().toDataURL();
async function Submit(){ cropper.getCroppedCanvas().toBlob((blob) => {
newAvatar = blob;
}, 'image/jpeg');
} }
showCroppingImgDiv = false
};
</script> </script>
<body> <body>
{#if showSubmitFiled} {#if showCroppingImgDiv}
<div class="backgroundBlur"></div>
<div class="croppingDiv">
<img class="cropAvatar" bind:this={imageElement} alt="Image to crop" />
<button class="cropButton" on:click={getCroppedImage}>Подтвердить</button>
</div>
{/if}
{#if showSubmitDiv}
<div class="backgroundBlur"></div> <div class="backgroundBlur"></div>
<div class="submitPassword"> <div class="submitPassword">
<h2>Введите старый пароль</h2> <h2>Подтвердите кодом из почты</h2>
<input type="password" id="oldPassword" placeholder="Старый пароль"> <input bind:value={code} type="password" id="oldPassword" placeholder="Код">
<button on:click={Submit}>Отправить</button> <button on:click={submit}>Отправить</button>
</div> </div>
{/if} {/if}
@ -79,9 +168,19 @@
<div class="avatarDiv"> <div class="avatarDiv">
<h2>изменить аватарку</h2> <h2>изменить аватарку</h2>
<button class="changeAvatar" on:click={() => document.getElementById('fileInput').click()}> <button class="changeAvatar" on:click={() => document.getElementById('fileInput').click()}>
{#if croppedImage != ""}
<img class="newAvatar" src="{croppedImage}" alt="новая ава">
{:else}
+ +
{/if}
</button> </button>
<div class="avatarsHistory">
{#each avatars as avatar}
<img class="avatarHistory" src="{avatar.avatar_url}" alt="ава">
{/each}
</div>
<input type="file" accept="image/*" id="fileInput" <input type="file" accept="image/*" id="fileInput"
on:change={handleFileChange} style="display: none;"> on:change={handleFileChange} style="display: none;">
</div> </div>
@ -89,21 +188,21 @@
<div class="textDiv"> <div class="textDiv">
<div> <div>
<h3>ник</h3> <h3>ник</h3>
<input type="text" placeholder={userName}> <input bind:value={newName} type="name" placeholder={oldName}>
</div> </div>
<div> <div>
<h3>почта</h3> <h3>почта</h3>
<input type="text" placeholder={userEmail}> <input bind:value={newEmail} type="email" placeholder={oldEmail}>
</div> </div>
<div> <div>
<h2>новый пароль</h2> <h2>новый пароль</h2>
<input type="text" placeholder="новый пароль"> <input bind:value={newPassword} type="password" placeholder="новый пароль">
</div> </div>
</div> </div>
</div> </div>
<div class="finishButton"> <div class="finishButton">
<button on:click={changingData}>Подтвердить</button> <button on:click={changingData}>Подтвердить</button>
<button>Отменить</button> <button on:click={cancel}>Отменить</button>
</div> </div>
</div> </div>
</div> </div>
@ -115,6 +214,84 @@
<style lang="scss"> <style lang="scss">
.cropper-modal {
background-color: #101010;
opacity: 0.5;
}
.cropButton{
padding-top: 15px;
}
.cropAvatar{
border-radius: 15px;
width: 500px;
height: 500px;
}
.croppingDiv{
z-index: 5;
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
left: 50%; top: 50%;
transform: (-50%,-50%);
transform: translate(-50%,-50%);
padding: 20px;
max-height: 90%;
max-width: 90%;
border: 1px solid transparent;
background:
linear-gradient(#101010, #101010) padding-box,
var(--gradient) border-box;
border-radius: 15px;
}
.newAvatar{
width: 75px;
height: 75px;
border-radius: 15px;
}
.avatarsHistory{
display: flex;
flex-direction: row;
width: 50%;
background-color: #FFFFFF0a;
border-radius: 15px;
overflow-y: hidden;
}
.avatarHistory{
width: 75px;
height: 75px;
padding: 3px;
border-radius: 15px;
}
.changeAvatar{
width: 75px;
height: 75px;
border: 1px solid transparent;
background:
linear-gradient(#101010, #101010) padding-box,
var(--gradient) border-box;
border-radius: 15px;
background-repeat: no-repeat;
background-attachment: fixed;
display: flex;
justify-content: center;
align-items: center;
}
button{ button{
font-size: 32px; font-size: 32px;
} }
@ -127,7 +304,7 @@ button{
height: 100%; height: 100%;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
z-index: 5; z-index: 4;
} }
#oldPassword{ #oldPassword{
@ -154,30 +331,30 @@ button{
background: background:
linear-gradient(#101010, #101010) padding-box, linear-gradient(#101010, #101010) padding-box,
var(--gradient) border-box; var(--gradient) border-box;
border-radius: 10px; border-radius: 15px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-attachment: fixed; background-attachment: fixed;
} }
.changeAvatar{ .submitPassword::before{
width: 75px; content: '';
height: 75px; position: absolute;
border: 1px solid transparent; background-image: url('./noise.png');
background: background-repeat: repeat;
linear-gradient(#101010, #101010) padding-box, width: 100%;
var(--gradient) border-box; height: 100%;
border-radius: 10px; border-radius: 15px;
background-repeat: no-repeat; opacity: 0.01;
background-attachment: fixed; pointer-events: none;
} }
.avatarDiv{ .avatarDiv{
height: 60%; height: 60%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between;
align-items: center; align-items: center;
//background-color: red;
} }
input { input {
@ -216,8 +393,8 @@ input {
height: 60%; height: 60%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-between;
//background-color: red; //background-color: blue;
} }
.button{ .button{
@ -278,6 +455,7 @@ input {
.header { .header {
height: 10%; height: 10%;
width: 85%; width: 85%;
z-index: 3;
} }
.mainDiv{ .mainDiv{
@ -318,7 +496,7 @@ input {
body{ body{
display: flexbox; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;

View file

@ -515,19 +515,6 @@ function helperDivShow(event, id, text, img, username) {
//top: -35px; //top: -35px;
} }
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, var(--blue), var(--purple));
background-repeat: no-repeat;
background-attachment: fixed;
border-radius: 15px;
}
::-webkit-scrollbar {
width: 3px;
}
.deleteAnswer{ .deleteAnswer{
padding: 0 0 0 10px; padding: 0 0 0 10px;
} }

View file

@ -0,0 +1,84 @@
<script>
import { onMount } from 'svelte';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
let imageElement;
let cropper;
let croppedImage;
let showCropMessage = false;
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
imageElement.src = e.target.result;
if (cropper) {
cropper.destroy();
}
cropper = new Cropper(imageElement, {
aspectRatio: 1,
viewMode: 1,
autoCropArea: 0, // Начальное значение для автообрезки 0
center: true,
zoomOnTouch: false,
zoomOnWheel: false,
cropBoxMovable: true,
cropBoxResizable: true,
background: false, // Убирает сеточный фон
autoCrop: false, // Изначально не показывать зону обрезки
ready: function () {
cropper.setCropBoxData({
width: 200,
height: 200,
left: (cropper.getContainerData().width - 200) / 2,
top: (cropper.getContainerData().height - 200) / 2,
});
cropper.crop(); // Включить зону обрезки
},
});
};
reader.readAsDataURL(file);
}
};
const getCroppedImage = () => {
if (cropper) {
croppedImage = cropper.getCroppedCanvas().toDataURL();
}
};
</script>
<div class="crop-container">
<input type="file" accept="image/*" on:change={handleFileChange} />
<img bind:this={imageElement} alt="Image to crop" />
</div>
<button on:click={getCroppedImage}>Crop Image</button>
{#if croppedImage}
<h3>Cropped Image</h3>
<img src={croppedImage} alt="Cropped Image" />
{/if}
<style>
img {
max-width: 100%;
display: block;
margin: 0 auto;
}
.crop-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 80vh; /* Настройка высоты по мере необходимости */
}
.crop-message {
color: white;
margin-top: 10px;
font-size: 1.2em;
}
</style>