mirror of
https://gitea.tendokyu.moe/Hay1tsme/artemis.git
synced 2026-02-09 01:07:40 +08:00
TL;DR avatar and userbox frontend pages can get hella slow when loading the first time when a ton of stuff is unlocked. Its driven primarily by all the images the server has to push to the client. To reduce the burden, these changes switch from using png to webp for all scaped images during import, reducing image sizes to roughly 20% of their png-equivalent. The filelist is long so here's a summary list of changes: - Replaced png assets with webp versions - Updated read.py to save assets as webp instead of png - Updated frontend.py and jinja to use webp instead of png - Added a conversion function ran by both the importer and the frontend on launch that looks for previously imported png files and converts them to webp. Only included for the sake of anyone who already did imports since the frontend improvements were introduced. - [bugfix] Fixed a css bug in the avatar jinja that affected Save/Reset button use on super narrow screens Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/234 Co-authored-by: daydensteve <daydensteve@gmail.com> Co-committed-by: daydensteve <daydensteve@gmail.com>
315 lines
12 KiB
Django/Jinja
315 lines
12 KiB
Django/Jinja
{% extends "core/templates/index.jinja" %}
|
|
{% block content %}
|
|
<style>
|
|
{% include 'titles/chuni/templates/css/chuni_style.css' %}
|
|
</style>
|
|
|
|
<div class="container">
|
|
{% include 'titles/chuni/templates/chuni_header.jinja' %}
|
|
|
|
<!-- USER BOX PREVIEW -->
|
|
<div class="row">
|
|
<div class="col-lg-8 m-auto mt-3">
|
|
<div class="card bg-card rounded">
|
|
<table class="table-large table-rowdistinct">
|
|
<caption align="top">USER BOX</caption>
|
|
<tr><td colspan=2 style="height:240px;">
|
|
<!-- NAMEPLATE -->
|
|
<img id="preview_nameplate" class="userbox userbox-nameplate" src="">
|
|
|
|
<!-- TEAM -->
|
|
<img class="userbox userbox-teamframe" src="img/rank/team3.webp">
|
|
<div class="userbox userbox-teamname">{{team_name}}</div>
|
|
|
|
<!-- TROPHY/TITLE -->
|
|
<img id="preview_trophy_rank" class="userbox userbox-trophy" src="">
|
|
<div id="preview_trophy_name" class="userbox userbox-trophy userbox-trophy-name"></div>
|
|
|
|
<!-- NAME/RATING -->
|
|
<img class="userbox userbox-ratingframe" src="img/rank/rating0.webp">
|
|
<div class="userbox userbox-name">
|
|
<span class="userbox-name-level-label">Lv.</span>
|
|
{{ profile.level }} {{ profile.userName }}
|
|
</div>
|
|
<div class="userbox userbox-rating rating rating-rank{{ rating_rank }}">
|
|
<span class="userbox-rating-label">RATING</span>
|
|
{{ profile.playerRating/100 }}
|
|
</div>
|
|
|
|
<!-- CHARACTER -->
|
|
<img class="userbox userbox-charaframe" src="img/character-bg.webp">
|
|
<img id="preview_character" class="userbox userbox-chara" src="">
|
|
</td></tr>
|
|
|
|
<tr><td>Nameplate:</td><td style="width: 80%;"><div id="name_nameplate"></div></td></tr>
|
|
|
|
<tr><td>Trophy:</td><td><div id="name_trophy">
|
|
<select name="trophy" id="trophy" onclick="changeTrophy()" style="width:100%;">
|
|
{% for item in trophies.values() %}
|
|
<option value="{{ item["id"] }}" class="trophy-rank{{ item["rarity"] }}">{{ item["name"] }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div></td></tr>
|
|
{% if cur_version >= 17 %} <!-- SubTrophies introduced in VERSE -->
|
|
<tr><td>Trophy Sub 1:</td><td><div id="name_trophy">
|
|
<select name="trophy-sub-1" id="trophy-sub-1" onclick="changeTrophySub1()" style="width:100%;">
|
|
<option value="-1"></option>
|
|
{% for item in trophies.values() %}
|
|
<option value="{{ item["id"] }}" class="trophy-rank{{ item["rarity"] }}">{{ item["name"] }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div></td></tr>
|
|
|
|
<tr><td>Trophy Sub 2:</td><td><div id="name_trophy">
|
|
<select name="trophy-sub-2" id="trophy-sub-2" onclick="changeTrophySub2()" style="width:100%;">
|
|
<option value="-1"></option>
|
|
{% for item in trophies.values() %}
|
|
<option value="{{ item["id"] }}" class="trophy-rank{{ item["rarity"] }}">{{ item["name"] }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div></td></tr>
|
|
{% endif %}
|
|
|
|
<tr><td>Character:</td><td><div id="name_character"></div></td></tr>
|
|
|
|
<tr><td colspan=2 style="padding:8px 0px; text-align: center;">
|
|
<button id="save-btn" class="btn btn-primary" style="width:140px;" onClick="saveUserbox()">SAVE</button>
|
|
<button id="reset-btn" class="btn btn-danger" style="width:140px;" onClick="resetUserbox()">RESET</button>
|
|
</td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- USERBOX SELECTION -->
|
|
<div class="row col-lg-8 m-auto mt-3 scrolling-lists-lg card bg-card rounded">
|
|
|
|
<!-- NAMEPLATE -->
|
|
<button class="collapsible">Nameplate: {{ nameplates|length }}/{{ total_nameplates }}</button>
|
|
<div id="scrollable-nameplate" class="collapsible-content">
|
|
{% for item in nameplates.values() %}
|
|
<img id="nameplate-{{ item["id"] }}" style="padding: 8px 8px;" onclick="changeItem('nameplate', '{{ item["id"] }}', '{{ item["name"] }}', '{{ item["texturePath"] }}')" src="img/nameplate/{{ item["texturePath"] }}" alt="{{ item["name"] }}">
|
|
<span id="nameplate-br-{{ loop.index }}"></span>
|
|
{% endfor %}
|
|
</div>
|
|
<hr>
|
|
|
|
<!-- CHARACTER -->
|
|
<button class="collapsible">Character: {{ characters|length }}/{{ total_characters }}</button>
|
|
<div id="scrollable-character" class="collapsible-content">
|
|
{% for item in characters.values() %}
|
|
<img id="character-{{ item["id"] }}" onclick="changeItem('character', '{{ item["id"] }}', '{{ item["name"] }}', '{{ item["iconPath"] }}')" src="img/character/{{ item["iconPath"] }}" alt="{{ item["name"] }}">
|
|
<span id="character-br-{{ loop.index }}"></span>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% if error is defined %}
|
|
{% include "core/templates/widgets/err_banner.jinja" %}
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if nameplates|length == 0 or characters|length == 0 %}
|
|
<script>
|
|
// Server DB lacks necessary info. Maybe importer never got ran for this verison?
|
|
document.getElementById("name_nameplate").innerHTML = "Server DB needs upgraded or is not populated with necessary data";
|
|
</script>
|
|
{% else %}
|
|
<script>
|
|
{% include 'titles/chuni/templates/scripts/collapsibles.js' %}
|
|
|
|
///
|
|
/// This script handles all updates to the user box
|
|
///
|
|
total_items = 0;
|
|
orig_id = 1;
|
|
orig_name = 2;
|
|
orig_img = 3;
|
|
curr_id = 4;
|
|
curr_name = 5;
|
|
curr_img = 6;
|
|
userbox_components = {
|
|
// [total_items, orig_id, orig_name, orig_img, curr_id, curr_name, curr_img]
|
|
"nameplate":["{{ nameplates|length }}",
|
|
"{{ profile.nameplateId }}",
|
|
"{{ nameplates[profile.nameplateId]["name"] }}",
|
|
"{{ nameplates[profile.nameplateId]["texturePath"] }}", "", "", ""],
|
|
|
|
"character":["{{ characters|length }}",
|
|
"{{ profile.characterId }}",
|
|
"{{ characters[profile.characterId]["name"] }}",
|
|
"{{ characters[profile.characterId]["iconPath"] }}", "", "", ""]
|
|
};
|
|
types = Object.keys(userbox_components);
|
|
orig_trophy = curr_trophy = "{{ profile.trophyId }}";
|
|
orig_trophy_sub_1 = curr_trophy_sub_1 = "{{ profile.trophyIdSub1 }}";
|
|
orig_trophy_sub_2 = curr_trophy_sub_2 = "{{ profile.trophyIdSub2 }}";
|
|
curr_trophy_img = "";
|
|
curr_trophy_name = "";
|
|
|
|
function enableButtons(enabled) {
|
|
document.getElementById("reset-btn").disabled = !enabled;
|
|
document.getElementById("save-btn").disabled = !enabled;
|
|
}
|
|
|
|
function changeItem(type, id, name, img) {
|
|
// clear select style for old component
|
|
var element = document.getElementById(type + "-" + userbox_components[type][curr_id]);
|
|
if (element) {
|
|
element.style.backgroundColor="inherit";
|
|
}
|
|
|
|
// set new component
|
|
userbox_components[type][curr_id] = id;
|
|
userbox_components[type][curr_name] = name;
|
|
userbox_components[type][curr_img] = img;
|
|
|
|
// update select style for new accessory
|
|
element = document.getElementById(type + "-" + id);
|
|
if (element) {
|
|
element.style.backgroundColor="#5F5";
|
|
}
|
|
|
|
// Update the userbox preview and enable buttons
|
|
updatePreview();
|
|
if (id != userbox_components[type][orig_id]) {
|
|
enableButtons(true);
|
|
}
|
|
}
|
|
|
|
function getRankImage(selected_rank) {
|
|
for (const x of Array(12).keys()) {
|
|
if (selected_rank.classList.contains("trophy-rank" + x.toString())) {
|
|
return "rank" + x.toString() + ".webp";
|
|
}
|
|
}
|
|
return "rank0.webp"; // shouldnt ever happen
|
|
}
|
|
|
|
function changeTrophy() {
|
|
var trophy_element = document.getElementById("trophy");
|
|
|
|
curr_trophy = trophy_element.value;
|
|
curr_trophy_name = trophy_element[trophy_element.selectedIndex].innerText
|
|
curr_trophy_img = getRankImage(trophy_element[trophy_element.selectedIndex]);
|
|
updatePreview();
|
|
if (curr_trophy != orig_trophy) {
|
|
enableButtons(true);
|
|
}
|
|
}
|
|
|
|
function changeTrophySub1() {
|
|
var trophy_element = document.getElementById("trophy-sub-1");
|
|
|
|
curr_trophy_sub_1 = trophy_element.value;
|
|
curr_trophy_img = getRankImage(trophy_element[trophy_element.selectedIndex]);
|
|
curr_trophy_name = trophy_element[trophy_element.selectedIndex].innerText
|
|
updatePreview();
|
|
if (curr_trophy_sub_1 != orig_trophy_sub_1) {
|
|
enableButtons(true);
|
|
}
|
|
}
|
|
|
|
function changeTrophySub2() {
|
|
var trophy_element = document.getElementById("trophy-sub-2");
|
|
|
|
curr_trophy_sub_2 = trophy_element.value;
|
|
curr_trophy_img = getRankImage(trophy_element[trophy_element.selectedIndex]);
|
|
curr_trophy_name = trophy_element[trophy_element.selectedIndex].innerText
|
|
updatePreview();
|
|
if (curr_trophy_sub_2 != orig_trophy_sub_2) {
|
|
enableButtons(true);
|
|
}
|
|
}
|
|
|
|
function resetUserbox() {
|
|
for (const type of types) {
|
|
changeItem(type, userbox_components[type][orig_id], userbox_components[type][orig_name], userbox_components[type][orig_img]);
|
|
}
|
|
// reset trophy
|
|
document.getElementById("trophy").value = orig_trophy;
|
|
document.getElementById("trophy-sub-1").value = orig_trophy_sub_1;
|
|
document.getElementById("trophy-sub-2").value = orig_trophy_sub_2;
|
|
changeTrophy();
|
|
// disable the save/reset buttons until something changes
|
|
enableButtons(false);
|
|
}
|
|
|
|
function updatePreview() {
|
|
for (const type of types) {
|
|
document.getElementById("preview_" + type).src = "img/" + type + "/" + userbox_components[type][curr_img];
|
|
document.getElementById("name_" + type).innerHTML = userbox_components[type][curr_name];
|
|
}
|
|
document.getElementById("preview_trophy_rank").src = "img/rank/" + curr_trophy_img;
|
|
document.getElementById("preview_trophy_name").innerHTML = curr_trophy_name;
|
|
}
|
|
|
|
function saveUserbox() {
|
|
$.post("/game/chuni/update.userbox", { nameplate: userbox_components["nameplate"][curr_id],
|
|
trophy: curr_trophy,
|
|
trophySub1: curr_trophy_sub_1,
|
|
trophySub2: curr_trophy_sub_2,
|
|
character: userbox_components["character"][curr_id] })
|
|
.done(function (data) {
|
|
// set the current as the original and disable buttons
|
|
for (const type of types) {
|
|
userbox_components[type][orig_id] = userbox_components[type][curr_id];
|
|
userbox_components[type][orig_name] = userbox_components[type][orig_name];
|
|
userbox_components[type][orig_img] = userbox_components[type][curr_img];
|
|
}
|
|
orig_trophy = curr_trophy;
|
|
orig_trophy_sub_1 = curr_trophy_sub_1;
|
|
orig_trophy_sub_2 = curr_trophy_sub_2;
|
|
enableButtons(false);
|
|
})
|
|
.fail(function () {
|
|
alert("Failed to save userbox.");
|
|
});
|
|
}
|
|
|
|
function resizePage() {
|
|
//
|
|
// Handles item organization in the collapsible scrollables to try to keep the items-per-row presentable
|
|
//
|
|
// @note Yes, we could simply let the div overflow like usual. This could however get really nasty looking
|
|
// when dealing with something like userbox characters where there are 1000s of possible items being
|
|
// display. This approach gives us full control over where items in the div wrap, allowing us to try
|
|
// to keep things presentable.
|
|
//
|
|
for (const type of types) {
|
|
var numPerRow = Math.floor(document.getElementById("scrollable-" + type).offsetWidth / 132);
|
|
|
|
// Dont put fewer than 4 per row
|
|
numPerRow = Math.max(numPerRow, 4);
|
|
|
|
// Dont populate more than 8 rows
|
|
numPerRow = Math.max(numPerRow, Math.ceil(userbox_components[type][total_items] / 8));
|
|
|
|
// update the locations of the <br>
|
|
for (var i = 1; document.getElementById(type + "-br-" + i) != null; i++) {
|
|
var spanBr = document.getElementById(type + "-br-" + i);
|
|
if ( i % numPerRow == 0 ) {
|
|
spanBr.innerHTML = "<br>";
|
|
} else {
|
|
spanBr.innerHTML = "";
|
|
}
|
|
}
|
|
}
|
|
// update the max height for any currently visible containers
|
|
Collapsibles.updateAllHeights();
|
|
}
|
|
resizePage();
|
|
window.addEventListener('resize', resizePage);
|
|
|
|
// Set initial preview for current userbox
|
|
resetUserbox();
|
|
// Initialize scroll on all current items so we can see the selected ones
|
|
for (const type of types) {
|
|
document.getElementById("scrollable-" + type).scrollLeft = document.getElementById(type + "-" + userbox_components[type][curr_id]).offsetLeft;
|
|
}
|
|
|
|
Collapsibles.expandAll();
|
|
</script>
|
|
{% endif %}
|
|
{% endblock content %} |