Добавлены функции кэширования аватарок для улучшения производительности

- Реализованы функции для кэширования аватарок пользователей с использованием localStorage.
- Добавлены методы для получения, очистки и преобразования аватарок в формат base64.
- Обновлены интерфейсы загрузки и отображения аватарок с поддержкой кэширования.
- Обновлены зависимости, включая добавление библиотеки sharp для обработки изображений.
This commit is contained in:
Fovway 2025-10-24 23:14:18 +07:00
parent 5b76167c3d
commit bfa15465f8
5 changed files with 716 additions and 13 deletions

489
package-lock.json generated
View File

@ -32,7 +32,8 @@
"sqlite3": "^5.1.7" "sqlite3": "^5.1.7"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.10" "nodemon": "^3.1.10",
"sharp": "^0.34.4"
} }
}, },
"node_modules/@codemirror/autocomplete": { "node_modules/@codemirror/autocomplete": {
@ -505,6 +506,16 @@
"w3c-keyname": "^2.2.4" "w3c-keyname": "^2.2.4"
} }
}, },
"node_modules/@emnapi/runtime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz",
"integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==",
"dev": true,
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@gar/promisify": { "node_modules/@gar/promisify": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@ -528,6 +539,433 @@
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==" "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
}, },
"node_modules/@img/colour": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
"dev": true,
"engines": {
"node": ">=18"
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz",
"integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.3"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz",
"integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.3"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz",
"integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz",
"integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz",
"integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz",
"integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz",
"integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz",
"integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz",
"integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz",
"integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz",
"integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz",
"integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.3"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz",
"integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.3"
}
},
"node_modules/@img/sharp-linux-ppc64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz",
"integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.3"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz",
"integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.3"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz",
"integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.3"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz",
"integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.3"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz",
"integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.3"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz",
"integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==",
"cpu": [
"wasm32"
],
"dev": true,
"optional": true,
"dependencies": {
"@emnapi/runtime": "^1.5.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz",
"integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz",
"integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz",
"integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@lezer/common": { "node_modules/@lezer/common": {
"version": "0.16.1", "version": "0.16.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.16.1.tgz",
@ -2902,6 +3340,48 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
}, },
"node_modules/sharp": {
"version": "0.34.4",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz",
"integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@img/colour": "^1.0.0",
"detect-libc": "^2.1.0",
"semver": "^7.7.2"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.4",
"@img/sharp-darwin-x64": "0.34.4",
"@img/sharp-libvips-darwin-arm64": "1.2.3",
"@img/sharp-libvips-darwin-x64": "1.2.3",
"@img/sharp-libvips-linux-arm": "1.2.3",
"@img/sharp-libvips-linux-arm64": "1.2.3",
"@img/sharp-libvips-linux-ppc64": "1.2.3",
"@img/sharp-libvips-linux-s390x": "1.2.3",
"@img/sharp-libvips-linux-x64": "1.2.3",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.3",
"@img/sharp-libvips-linuxmusl-x64": "1.2.3",
"@img/sharp-linux-arm": "0.34.4",
"@img/sharp-linux-arm64": "0.34.4",
"@img/sharp-linux-ppc64": "0.34.4",
"@img/sharp-linux-s390x": "0.34.4",
"@img/sharp-linux-x64": "0.34.4",
"@img/sharp-linuxmusl-arm64": "0.34.4",
"@img/sharp-linuxmusl-x64": "0.34.4",
"@img/sharp-wasm32": "0.34.4",
"@img/sharp-win32-arm64": "0.34.4",
"@img/sharp-win32-ia32": "0.34.4",
"@img/sharp-win32-x64": "0.34.4"
}
},
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@ -3263,6 +3743,13 @@
"nodetouch": "bin/nodetouch.js" "nodetouch": "bin/nodetouch.js"
} }
}, },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"optional": true
},
"node_modules/tunnel-agent": { "node_modules/tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",

View File

@ -38,6 +38,7 @@
"sqlite3": "^5.1.7" "sqlite3": "^5.1.7"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.1.10" "nodemon": "^3.1.10",
"sharp": "^0.34.4"
} }
} }

View File

@ -1,3 +1,73 @@
// Кэширование аватарки
const AVATAR_CACHE_KEY = "avatar_cache";
const AVATAR_TIMESTAMP_KEY = "avatar_timestamp";
// Функция для кэширования аватарки
async function cacheAvatar(avatarUrl) {
try {
const response = await fetch(avatarUrl);
if (!response.ok) return false;
const blob = await response.blob();
const base64 = await blobToBase64(blob);
const cacheData = {
base64: base64,
timestamp: Date.now(),
url: avatarUrl
};
localStorage.setItem(AVATAR_CACHE_KEY, JSON.stringify(cacheData));
localStorage.setItem(AVATAR_TIMESTAMP_KEY, Date.now().toString());
return true;
} catch (error) {
console.error("Ошибка кэширования аватарки:", error);
return false;
}
}
// Функция для получения аватарки из кэша
function getCachedAvatar() {
try {
const cacheData = localStorage.getItem(AVATAR_CACHE_KEY);
const timestamp = localStorage.getItem(AVATAR_TIMESTAMP_KEY);
if (!cacheData || !timestamp) return null;
const data = JSON.parse(cacheData);
const cacheAge = Date.now() - parseInt(timestamp);
// Кэш действителен 24 часа (86400000 мс)
if (cacheAge > 24 * 60 * 60 * 1000) {
clearAvatarCache();
return null;
}
return data;
} catch (error) {
console.error("Ошибка получения аватарки из кэша:", error);
clearAvatarCache();
return null;
}
}
// Функция для очистки кэша аватарки
function clearAvatarCache() {
localStorage.removeItem(AVATAR_CACHE_KEY);
localStorage.removeItem(AVATAR_TIMESTAMP_KEY);
}
// Преобразование Blob в base64
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
// DOM элементы // DOM элементы
const noteInput = document.getElementById("noteInput"); const noteInput = document.getElementById("noteInput");
const saveBtn = document.getElementById("saveBtn"); const saveBtn = document.getElementById("saveBtn");
@ -1339,17 +1409,16 @@ async function renderNotes(notes) {
note.is_pinned ? "-off" : "" note.is_pinned ? "-off" : ""
}"></span> }"></span>
</div> </div>
<div id="archiveBtn" class="notesHeaderBtn" data-id="${
note.id
}" title="Архивировать">
<span class="iconify" data-icon="mdi:archive"></span>
</div>
<div id="editBtn" class="notesHeaderBtn" data-id="${ <div id="editBtn" class="notesHeaderBtn" data-id="${
note.id note.id
}">Ред.</div> }" title="Редактировать">
<div id="deleteBtn" class="notesHeaderBtn" data-id="${ <span class="iconify" data-icon="mdi:pencil"></span>
</div>
<div id="archiveBtn" class="notesHeaderBtn" data-id="${
note.id note.id
}">Удал.</div> }" title="В архив">
<span class="iconify" data-icon="mdi:delete"></span>
</div>
</div> </div>
</div> </div>
<div class="textNote" data-original-content="${note.content.replace( <div class="textNote" data-original-content="${note.content.replace(
@ -2570,7 +2639,24 @@ async function loadUserInfo() {
// Показываем аватарку или плейсхолдер // Показываем аватарку или плейсхолдер
if (user.avatar) { if (user.avatar) {
if (userAvatar && userAvatarContainer) { if (userAvatar && userAvatarContainer) {
userAvatar.src = user.avatar; // Проверяем, есть ли аватарка в кэше
const cachedAvatar = getCachedAvatar();
if (cachedAvatar && cachedAvatar.url === user.avatar) {
// Используем кэшированную аватарку
userAvatar.src = cachedAvatar.base64;
console.log("Аватарка загружена из кэша (notes)");
} else {
// Загружаем аватарку с сервера и кэшируем
userAvatar.src = user.avatar;
// Кэшируем в фоне
cacheAvatar(user.avatar).then(success => {
if (success) {
console.log("Аватарка закэширована (notes)");
}
});
}
userAvatarContainer.style.display = "block"; userAvatarContainer.style.display = "block";
if (userAvatarPlaceholder) { if (userAvatarPlaceholder) {
userAvatarPlaceholder.style.display = "none"; userAvatarPlaceholder.style.display = "none";
@ -2583,6 +2669,8 @@ async function loadUserInfo() {
if (userAvatarContainer) { if (userAvatarContainer) {
userAvatarContainer.style.display = "none"; userAvatarContainer.style.display = "none";
} }
// Очищаем кэш, если аватарки нет
clearAvatarCache();
} }
// Делаем аватарку и плейсхолдер кликабельными для перехода в профиль // Делаем аватарку и плейсхолдер кликабельными для перехода в профиль

View File

@ -12,6 +12,76 @@ const confirmPasswordInput = document.getElementById("confirmPassword");
const changePasswordBtn = document.getElementById("changePasswordBtn"); const changePasswordBtn = document.getElementById("changePasswordBtn");
const messageContainer = document.getElementById("messageContainer"); const messageContainer = document.getElementById("messageContainer");
// Кэширование аватарки
const AVATAR_CACHE_KEY = "avatar_cache";
const AVATAR_TIMESTAMP_KEY = "avatar_timestamp";
// Функция для кэширования аватарки
async function cacheAvatar(avatarUrl) {
try {
const response = await fetch(avatarUrl);
if (!response.ok) return false;
const blob = await response.blob();
const base64 = await blobToBase64(blob);
const cacheData = {
base64: base64,
timestamp: Date.now(),
url: avatarUrl
};
localStorage.setItem(AVATAR_CACHE_KEY, JSON.stringify(cacheData));
localStorage.setItem(AVATAR_TIMESTAMP_KEY, Date.now().toString());
return true;
} catch (error) {
console.error("Ошибка кэширования аватарки:", error);
return false;
}
}
// Функция для получения аватарки из кэша
function getCachedAvatar() {
try {
const cacheData = localStorage.getItem(AVATAR_CACHE_KEY);
const timestamp = localStorage.getItem(AVATAR_TIMESTAMP_KEY);
if (!cacheData || !timestamp) return null;
const data = JSON.parse(cacheData);
const cacheAge = Date.now() - parseInt(timestamp);
// Кэш действителен 24 часа (86400000 мс)
if (cacheAge > 24 * 60 * 60 * 1000) {
clearAvatarCache();
return null;
}
return data;
} catch (error) {
console.error("Ошибка получения аватарки из кэша:", error);
clearAvatarCache();
return null;
}
}
// Функция для очистки кэша аватарки
function clearAvatarCache() {
localStorage.removeItem(AVATAR_CACHE_KEY);
localStorage.removeItem(AVATAR_TIMESTAMP_KEY);
}
// Преобразование Blob в base64
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
// Lazy loading для изображений // Lazy loading для изображений
function initLazyLoading() { function initLazyLoading() {
// Проверяем поддержку Intersection Observer API // Проверяем поддержку Intersection Observer API
@ -84,7 +154,24 @@ async function loadProfile() {
// Обрабатываем аватарку // Обрабатываем аватарку
if (user.avatar) { if (user.avatar) {
avatarImage.src = user.avatar; // Проверяем, есть ли аватарка в кэше
const cachedAvatar = getCachedAvatar();
if (cachedAvatar && cachedAvatar.url === user.avatar) {
// Используем кэшированную аватарку
avatarImage.src = cachedAvatar.base64;
console.log("Аватарка загружена из кэша");
} else {
// Загружаем аватарку с сервера и кэшируем
avatarImage.src = user.avatar;
// Кэшируем в фоне
cacheAvatar(user.avatar).then(success => {
if (success) {
console.log("Аватарка закэширована");
}
});
}
avatarImage.style.display = "block"; avatarImage.style.display = "block";
avatarPlaceholder.style.display = "none"; avatarPlaceholder.style.display = "none";
deleteAvatarBtn.style.display = "inline-block"; deleteAvatarBtn.style.display = "inline-block";
@ -92,6 +179,8 @@ async function loadProfile() {
avatarImage.style.display = "none"; avatarImage.style.display = "none";
avatarPlaceholder.style.display = "inline-flex"; avatarPlaceholder.style.display = "inline-flex";
deleteAvatarBtn.style.display = "none"; deleteAvatarBtn.style.display = "none";
// Очищаем кэш, если аватарки нет
clearAvatarCache();
} }
} catch (error) { } catch (error) {
console.error("Ошибка загрузки профиля:", error); console.error("Ошибка загрузки профиля:", error);
@ -137,11 +226,18 @@ avatarInput.addEventListener("change", async function (event) {
const result = await response.json(); const result = await response.json();
// Обновляем отображение аватарки // Обновляем отображение аватарки
avatarImage.src = result.avatar + "?t=" + Date.now(); // Добавляем timestamp для обновления кэша avatarImage.src = result.avatar + "?t=" + Date.now(); // Добавляем timestamp для обновления кэша браузера
avatarImage.style.display = "block"; avatarImage.style.display = "block";
avatarPlaceholder.style.display = "none"; avatarPlaceholder.style.display = "none";
deleteAvatarBtn.style.display = "inline-block"; deleteAvatarBtn.style.display = "inline-block";
// Обновляем кэш с новой аватаркой
cacheAvatar(result.avatar).then(success => {
if (success) {
console.log("Новая аватарка закэширована");
}
});
showMessage("Аватарка успешно загружена", "success"); showMessage("Аватарка успешно загружена", "success");
} catch (error) { } catch (error) {
console.error("Ошибка загрузки аватарки:", error); console.error("Ошибка загрузки аватарки:", error);
@ -173,6 +269,9 @@ deleteAvatarBtn.addEventListener("click", async function () {
avatarPlaceholder.style.display = "inline-flex"; avatarPlaceholder.style.display = "inline-flex";
deleteAvatarBtn.style.display = "none"; deleteAvatarBtn.style.display = "none";
// Очищаем кэш аватарки
clearAvatarCache();
showMessage("Аватарка успешно удалена", "success"); showMessage("Аватарка успешно удалена", "success");
} catch (error) { } catch (error) {
console.error("Ошибка удаления аватарки:", error); console.error("Ошибка удаления аватарки:", error);

View File

@ -123,6 +123,34 @@ header .iconify[data-icon="mdi:account-plus"] {
color: #0288d1; color: #0288d1;
} }
.btnMarkdown .iconify[data-icon="mdi:format-strikethrough"] {
color: #9c27b0;
}
.btnMarkdown .iconify[data-icon="mdi:format-list-numbered"] {
color: #4caf50;
}
.btnMarkdown .iconify[data-icon="mdi:checkbox-marked-outline"] {
color: #ff9800;
}
.btnMarkdown .iconify[data-icon="mdi:image-plus"] {
color: #2196f3;
}
.btnMarkdown .iconify[data-icon="mdi:eye"] {
color: #607d8b;
}
.notesHeaderBtn .iconify[data-icon="mdi:pencil"] {
color: #2196f3;
}
.notesHeaderBtn .iconify[data-icon="mdi:delete"] {
color: #dc3545;
}
header { header {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;