diff --git a/package.json b/package.json index 5875040..8027168 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "d2-synergy", - "version": "0.5.0", + "version": "0.5.6", "description": "[![Version](https://img.shields.io/badge/Version-ALPHA-yellow)](https://github.com/brendanprice2003/D2Synergy_v0.3)\r [![API](https://img.shields.io/badge/API-Bungie.net-blue)](https://bungie-net.github.io/multi/index.html)", "main": "index.js", "scripts": { diff --git a/src/index.html b/src/index.html index 10e847e..1ab4677 100644 --- a/src/index.html +++ b/src/index.html @@ -10,8 +10,8 @@ - - + D2 Synergy diff --git a/src/scripts/modules/AddTableRow.js b/src/scripts/modules/AddTableRow.js index 5095c02..cb8d6e8 100644 --- a/src/scripts/modules/AddTableRow.js +++ b/src/scripts/modules/AddTableRow.js @@ -1,16 +1,17 @@ // Add a new row to a defined table // @object {table}, @array {data} -export function AddTableRow(table, data = ['', '', '']) { +export function AddTableRow(table, data = ['', '']) { - // data param - // 0, Item Name / 1, Category / 2, Relation + // "data" parameter + // 0, Item name + // 1, Item relation count // Insert new row using data parameter const row = table.insertRow(-1); - // Insert data into cells - for (let i=0; i x !== this.getAttribute('data-containerName')); + // Toggle corresponding pages + let containerName = this.getAttribute('data-containerName'); + let containersToHide = containerNames.filter(x => x !== containerName); + for (let container of containersToHide) { document.getElementById(`${container}`).style.display = 'none'; }; - document.getElementById(this.getAttribute('data-containerName')).style.display = 'block'; + document.getElementById(containerName).style.display = 'block'; + + // Store the page as this is the page that was last visited (until it is changed) + CacheChangeItem('lastVisitedPage', containerName); }); // Challenges navbar control AddListener('navBarChallengesButton', 'click', function () { + // Toggle settings page in the case that it is open (accessibility) ToggleSettingsMenu(); - let containersToHide = containerNames.filter(x => x !== this.getAttribute('data-containerName')); + // Toggle corresponding pages + let containerName = this.getAttribute('data-containerName'); + let containersToHide = containerNames.filter(x => x !== containerName); + for (let container of containersToHide) { document.getElementById(`${container}`).style.display = 'none'; }; - document.getElementById(this.getAttribute('data-containerName')).style.display = 'block'; + document.getElementById(containerName).style.display = 'block'; + + // Store the page as this is the page that was last visited (until it is changed) + CacheChangeItem('lastVisitedPage', containerName); }); // Statistics navbar control AddListener('navBarStatisticsButton', 'click', function () { + // Toggle settings page in the case that it is open (accessibility) ToggleSettingsMenu(); - let containersToHide = containerNames.filter(x => x !== this.getAttribute('data-containerName')); + // Toggle corresponding pages + let containerName = this.getAttribute('data-containerName'); + let containersToHide = containerNames.filter(x => x !== containerName); + for (let container of containersToHide) { document.getElementById(`${container}`).style.display = 'none'; }; - document.getElementById(this.getAttribute('data-containerName')).style.display = 'block'; + document.getElementById(containerName).style.display = 'block'; + + // Store the page as this is the page that was last visited (until it is changed) + CacheChangeItem('lastVisitedPage', containerName); }); @@ -269,22 +345,14 @@ export async function AddEventListeners() { }); - // Character buttons - for (let i=0; i <= 2; i++) { - AddListener(`charContainer${i}`, 'click', () => { - LoadCharacter(i); - }); - }; - - // Title button (secret setting activation) - AddListener('navBarTitle', 'click', function () { - // secretCount++; - // if (secretCount >= 7) { - // document.getElementById('settingsSecretContainer').style.display = 'block'; - // CacheChangeItem('isSecretOn', true); - // }; - }); + // AddListener('navBarTitle', 'click', function () { + // secretCount++; + // if (secretCount >= 7) { + // document.getElementById('settingsSecretContainer').style.display = 'block'; + // CacheChangeItem('isSecretOn', true); + // }; + // }); // General settings button @@ -378,6 +446,33 @@ export async function AddEventListeners() { }); + // Remember last page checkbox + AddListener('checkboxRememberLastpage', 'change', function () { + + if (this.checked) { + + // Toggle boolean + CacheChangeItem('isRememberLastPageToggled', true); + + // Grey out default page dropdown and disable it + document.getElementById('defaultViewDropdownContainer').style.opacity = '50%'; + document.getElementById('defaultViewDropdown').options[0].disabled = true; + document.getElementById('defaultViewDropdown').options[1].disabled = true; + document.getElementById('defaultViewDropdown').options[2].disabled = true; + return; + }; + + // Uncheck = clear localStorage value + CacheChangeItem('isRememberLastPageToggled', false); + + // un-Grey out default page dropdown and disable it + document.getElementById('defaultViewDropdownContainer').style.opacity = '100%'; + document.getElementById('defaultViewDropdown').options[0].disabled = false; + document.getElementById('defaultViewDropdown').options[1].disabled = false; + document.getElementById('defaultViewDropdown').options[2].disabled = false; + }); + + // Use secret icons checkbox AddListener('checkboxUseSecretIcons', 'click', function () { @@ -547,55 +642,53 @@ export async function AddEventListeners() { AddDropdownEvent(dropdownContent, arrow, dropdownBoolean); }); - let currentlyShowingChunkIndex = 0; + + /* + Previous and Next arrows for seasonal challenges + Get maximum chunks that will be held in seasonalChallengeItems + ^ This value will the be the last index (page) + */ + let currentIndex = 0; + let lastIndex = Math.trunc(UserProfile.misc.challengesCount / 6) - 1; + // Show next chunk of seasonal challenges AddListener('nextSeasonalChallengePageButton', 'click', function () { - document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'none'; - if (currentlyShowingChunkIndex === 12) { - currentlyShowingChunkIndex = 0; + // Hide current page + document.getElementById(`challengeChunk${currentIndex}`).style.display = 'none'; + + // If first page, set index to last page + if (currentIndex === lastIndex) { + currentIndex = 0; } + + // Else, decrement index else { - currentlyShowingChunkIndex++; + currentIndex++; }; - document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'grid'; + + // Show current page + document.getElementById(`challengeChunk${currentIndex}`).style.display = 'grid'; }); // Show previous chunk of seasonal challenges AddListener('previousSeasonalChallengePageButton', 'click', function () { - document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'none'; - if (currentlyShowingChunkIndex === 0) { - currentlyShowingChunkIndex = 12; + // Hide current page + document.getElementById(`challengeChunk${currentIndex}`).style.display = 'none'; + + // If first page, set index to last page + if (currentIndex === 0) { + currentIndex = lastIndex; } + + // Else, decrement index else { - currentlyShowingChunkIndex--; + currentIndex--; }; - document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'grid'; - }); - - // Toggle table types (Filters) - AddListener('toggleTypePVE', 'click', function (e) { - - // Reverse boolean - relationsTable.toggles.pve = !relationsTable.toggles.pve; - - // Change innerHTML tag - document.getElementById('PVEButtonTag').innerHTML = `${relationsTable.toggles.pve ? '(on)' : '(off)'}`; - - // Rebuild table - relationsTable.BuildTable(); - }); - AddListener('toggleTypePVP', 'click', function (e) { - // Reverse boolean - relationsTable.toggles.pvp = !relationsTable.toggles.pvp; - - // Change innerHTML tag - document.getElementById('PVPButtonTag').innerHTML = `${relationsTable.toggles.pvp ? '(on)' : '(off)'}`; - - // Rebuild table - relationsTable.BuildTable(); + // Show current page + document.getElementById(`challengeChunk${currentIndex}`).style.display = 'grid'; }); }; @@ -603,6 +696,9 @@ export async function AddEventListeners() { // Configure defaults/Loads data from localStorage export async function BuildWorkspace() { + // Get time until weekly reset (timezone specific ofc) + document.getElementById('timeUntilWeeklyReset').innerHTML = `Weekly Reset: ${getNextTuesday()}`; + let rangeSlider = document.getElementById('accessibilityImageSizeSlider'), bountyImage = document.getElementById('accessibilityImageDemo'); @@ -660,12 +756,39 @@ export async function BuildWorkspace() { bountyImage.style.width = `${itemDisplay.itemDisplaySize}px`; // Set checkboxes to chosen state, from localStorage (userCache) - document.getElementById('checkboxRefreshOnInterval').checked = await CacheReturnItem('isRefreshOnIntervalToggled'); - document.getElementById('checkboxRefreshWhenFocused').checked = await CacheReturnItem('isRefreshOnFocusToggled'); - document.getElementById('checkboxIncludeExpiredBounties').checked = await CacheReturnItem('includeExpiredBounties'); - document.getElementById('checkboxIncludeSeasonalChallengesInTable').checked = await CacheReturnItem('includeSeasonalChallengesInTable'); + // Using ternary in the case that a boolean is not returned from CacheReturnItem + document.getElementById('toggleTypePVP').checked = await CacheReturnItem('includePvpInTable') ? true : false; + document.getElementById('toggleTypePVE').checked = await CacheReturnItem('includePveInTable') ? true : false; + document.getElementById('checkboxRefreshWhenFocused').checked = await CacheReturnItem('isRefreshOnFocusToggled') ? true : false; + document.getElementById('checkboxRefreshOnInterval').checked = await CacheReturnItem('isRefreshOnIntervalToggled') ? true : false; + document.getElementById('checkboxIncludeExpiredBountiesInYield').checked = await CacheReturnItem('includeExpiredBountiesInYield') ? true : false; + document.getElementById('checkboxIncludeExpiredBountiesInTable').checked = await CacheReturnItem('includeExpiredBountiesInTable') ? true : false; + document.getElementById('checkboxIncludeSeasonalChallengesInYield').checked = await CacheReturnItem('includeSeasonalChallengesInYield') ? true : false; + document.getElementById('checkboxIncludeSeasonalChallengesInTable').checked = await CacheReturnItem('includeSeasonalChallengesInTable') ? true : false; + + // Check if rememberLastPage is true + await CacheReturnItem('isRememberLastPageToggled') + .then((result) => { + + // Set the checkbox state using the boolean stored in localStorage + if (result) { - // Push cache results for defaultContenteView to variabGles + document.getElementById('checkboxRememberLastpage').checked = result; + + // Change the dropdown box above to correct state + document.getElementById('defaultViewDropdownContainer').style.opacity = '50%'; + document.getElementById('defaultViewDropdown').options[0].disabled = true; + document.getElementById('defaultViewDropdown').options[1].disabled = true; + document.getElementById('defaultViewDropdown').options[2].disabled = true; + }; + }) + .catch((error) => { + console.error(error); + }); + + + + // Parse defaultContentView results and push to DOM await CacheReturnItem('defaultContentView') .then((result) => { @@ -676,10 +799,28 @@ export async function BuildWorkspace() { document.getElementById('defaultViewDropdown').value = 'bountiesContainer'; return; }; + }) + .catch((error) => { + console.error(error); + }); - // Set default view to result from cache - // document.getElementById(`${result}`).style.display = 'block'; - // document.getElementById('defaultViewDropdown').value = result; + // Check if last page is being remembered, if so make the default the last visited page + await CacheReturnItem('isRememberLastPageToggled') + .then((result) => { + + // If true, hide all pages (elegantly!) then show the last visited one + if (result) { + CacheReturnItem('lastVisitedPage') + .then((pageName) => { + document.getElementById('bountiesContainer').style.display = 'none'; + document.getElementById('seasonalChallengesContainer').style.display = 'none'; + document.getElementById('statisticsContainer').style.display = 'none'; + document.getElementById(pageName).style.display = 'block'; + }) + .catch((error) => { + return error; + }); + }; }) .catch((error) => { console.error(error); @@ -704,299 +845,3 @@ export async function BuildWorkspace() { modifiersDropdownArrow.style.transform = 'rotate(0deg)'; }; - - -// DEPRECATED -// async function AddEventListenersDeprecated() { - -// log('AddEventListeners START'); -// // Add listeners for buttons -// for (let a = 0; a <= 2; a++) { -// document.getElementById(`charContainer${a}`).addEventListener('click', () => { -// LoadCharacter(a); -// }); -// }; - -// // Click on title to show secret setting -// document.getElementById('navBarTitle').addEventListener('click', () => { -// secretCount++; -// if (secretCount >= 5) { -// document.getElementById('secretIconCheckboxContainer').style.display = 'block'; -// CacheChangeItem('isSecretOn', true); -// }; -// }); - -// // Hover events for "Current Yield" -// document.getElementById('statsTitleQuery').addEventListener('mousemove', () => { -// document.getElementById('queryDiv').style.display = 'block'; -// }); -// document.getElementById('statsTitleQuery').addEventListener('mouseleave', () => { -// document.getElementById('queryDiv').style.display = 'none'; -// }); - -// // Hover events for "Net Breakdown" -// // Shared wisdom bonus hover -// const statSharedWisdom = document.getElementById('statSharedWisdom'); -// statSharedWisdom.addEventListener('mouseover', () => { -// document.getElementById('sharedWisdomPopupContainer').style.display = 'inline-block'; -// }); -// statSharedWisdom.addEventListener('mouseleave', () => { -// document.getElementById('sharedWisdomPopupContainer').style.display = 'none'; -// }); - -// // Ghost mod bonus hover -// const statGhostMod = document.getElementById('statGhostMod'); -// statGhostMod.addEventListener('mouseover', () => { -// document.getElementById('ghostModPopupContainer').style.display = 'inline-block'; -// }); -// statGhostMod.addEventListener('mouseleave', () => { -// document.getElementById('ghostModPopupContainer').style.display = 'none'; -// }); - -// // Bonus XP hover -// const statBonusXp = document.getElementById('statBonusXp'); -// statBonusXp.addEventListener('mouseover', () => { -// document.getElementById('BonusXpPopupContainer').style.display = 'inline-block'; -// }); -// statBonusXp.addEventListener('mouseleave', () => { -// document.getElementById('BonusXpPopupContainer').style.display = 'none'; -// }); - -// // Remove filters button -// document.getElementById('removeFiltersID').addEventListener('click', () => { - -// // Loop over charBounties and reverse filtered items -// charBounties.forEach(bounty => { -// if (eventFilters.grayedOutBounties) { -// eventFilters.grayedOutBounties.forEach(greyHash => { -// document.getElementById(`${bounty.hash}`).style.opacity = 'unset'; -// document.getElementById(`item_${bounty.hash}`).style.opacity = 'unset'; -// }); -// }; -// }); -// eventFilters.grayedOutBounties = []; // Clear array - - -// // Loop over bounty filters and reverse selected filers -// Object.keys(eventFilters.filterDivs).forEach(filter => { -// eventFilters.filterDivs[filter].element.style.color = 'rgb(138, 138, 138)'; -// }); -// }); - -// // Click event for "Bounties" side button -// document.getElementById('cgBounties').addEventListener('click', () => { - -// CacheReturnItem('defaultContentView') -// .then(result => { - -// // display: none the current view -// document.getElementById(result).style.display = 'none'; - -// // Show the bounties view -// document.getElementById('bountiesContainer').style.display = 'block'; - -// // Save the current view to cache -// CacheChangeItem('defaultContentView', 'bountiesContainer'); -// }); -// }); - -// // Click event for "Seasonal Challenges" side button -// document.getElementById('cgSeasonalChalls').addEventListener('click', () => { - -// CacheReturnItem('defaultContentView') -// .then(result => { - -// // display: none the current view -// document.getElementById(result).style.display = 'none'; - -// // Show the seasonalChallenges view -// document.getElementById('seasonalChallengesContainer').style.display = 'block'; - -// // Save the current view to cache -// CacheChangeItem('defaultContentView', 'seasonalChallengesContainer'); -// }); -// }); - -// // Toggle item filters button(s) (reverse container style) -// document.getElementById('btnHideFilters').addEventListener('click', () => { - -// let filterContentContainer = document.getElementById('filterContentContainer'); - -// // Check if boolean is true/false - change content -// if (filterContentContainer.style.display === 'block') { -// filterContentContainer.style.display = 'none'; -// } -// else if (filterContentContainer.style.display === 'none') { -// filterContentContainer.style.display = 'block'; -// }; -// }); - - -// // Settings toggles input listeners -// document.getElementById('checkboxRefreshWhenFocused').addEventListener('change', function () { - -// if (this.checked) { -// CacheChangeItem('isRefreshOnFocusToggled', true); -// } -// else { -// CacheChangeItem('isRefreshOnFocusToggled', false); -// }; -// }); - -// function passiveReload () { -// if (!document.hidden) { -// main(true) -// .catch((error) => { -// console.error(error); -// }); -// }; -// }; - -// // When the user changes focuses the tab again, reload -// document.addEventListener('visibilitychange', function () { - -// if (!document.hidden) { -// CacheReturnItem('isRefreshOnFocusToggled') -// .then(result => { - -// if (result === true) { -// document.getElementById('loadingIcon').style.display = 'none'; -// document.getElementById('loadingText').style.marginTop = '-65px'; -// passiveReload(); -// }; -// }); -// }; -// }); - -// // Refresh 2 minute interval event listener -// let refreshOnInterval; -// document.getElementById('checkboxRefreshOnInterval').addEventListener('change', function () { - -// if (this.checked) { - -// CacheChangeItem('isRefreshOnIntervalToggled', true); -// refreshOnInterval = setInterval( function () { -// main(true) -// .catch((error) => { -// console.error(error); -// }); -// }, 120_000); - -// document.getElementById('loadingIcon').style.display = 'none'; -// document.getElementById('loadingText').style.marginTop = '-65px'; -// } -// else if (!this.checked) { - -// CacheChangeItem('isRefreshOnIntervalToggled', false); -// clearInterval(refreshOnInterval); -// }; - -// }); - -// // (Default) Item size range slider -// let rangeSlider = document.getElementById('itemSizeSlider'), -// rangeValueField = document.getElementById('itemSizeField'), -// bountyImage = document.getElementById('settingsBountyImage'), -// defaultItemSize = 55; - -// // Default value -// rangeValueField.innerHTML = `${rangeSlider.value}px`; - -// // Input listener for range slider -// rangeSlider.oninput = function () { - -// bountyImage.style.width = `${this.value}px`; -// rangeValueField.innerHTML = `${this.value}px`; - -// Array.from(document.getElementsByClassName('bounty')).forEach(element => { -// element.style.width = `${this.value}px`; -// }); - -// CacheChangeItem('itemDisplaySize', this.value); -// }; - -// // Reset item size button event listener -// document.getElementById('resetItemSize').addEventListener('click', () => { - -// rangeSlider.value = defaultItemSize; -// bountyImage.style.width = `${defaultItemSize}px`; -// rangeValueField.innerHTML = `${defaultItemSize}px`; -// CacheChangeItem('itemDisplaySize', defaultItemSize); - -// Array.from(document.getElementsByClassName('bounty')).forEach(element => { -// element.style.width = `${defaultItemSize}px`; -// }); -// }); - -// // Form event for choosing the default content view -// document.getElementById('defaultViewDropdown').addEventListener('change', () => { - -// const contentViewsThatINeedToChange = [ -// 'bountiesContainer', -// 'seasonalChallengesContainer' -// ]; - -// const selectedValue = document.getElementById('defaultViewDropdown').value; - -// // Filter my current content views to display: none if they are not selectedValue -// contentViewsThatINeedToChange -// .forEach(value => { - -// if (value !== selectedValue) { -// document.getElementById(value).style.display = 'none'; -// return; -// }; - -// document.getElementById(value).style.display = 'block'; -// }); - -// // Save the chosen item to cache and change the current view to the chosen one -// CacheChangeItem('defaultContentView', selectedValue); -// document.getElementById(selectedValue).style.display = 'block'; -// }); - -// // Add listener for available vendor popup close button -// document.getElementById('availableVendorPopupClose').addEventListener('click', () => { -// document.getElementById('availableVendorPopupCanvas').style.display = 'none'; -// document.getElementById('availableVendorPopup').style.display = 'none'; -// }); - -// // Add an event listener to the canvas to close the popup (for ease of use) -// document.getElementById('availableVendorPopupCanvas').addEventListener('click', () => { -// document.getElementById('availableVendorPopupCanvas').style.display = 'none'; -// document.getElementById('availableVendorPopup').style.display = 'none'; -// }); - - -// // Add listener for next arrow to show previous chunk of seasonal challenges -// // Add listener for next arrow to show next chunk of seasonal challenges -// let currentlyShowingChunkIndex = 0; - -// document.getElementById('nextSeasonalChallengePageButton').addEventListener('click', () => { - -// document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'none'; -// if (currentlyShowingChunkIndex === 12) { -// currentlyShowingChunkIndex = 0; -// } -// else { -// currentlyShowingChunkIndex++; -// }; -// log(`currentlyShowingChunkIndex: ${currentlyShowingChunkIndex}`); -// document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'grid'; -// }); - -// document.getElementById('previousSeasonalChallengePageButton').addEventListener('click', () => { - -// document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'none'; -// if (currentlyShowingChunkIndex === 0) { -// currentlyShowingChunkIndex = 12; -// } -// else { -// currentlyShowingChunkIndex--; -// }; -// log(`currentlyShowingChunkIndex: ${currentlyShowingChunkIndex}`); -// document.getElementById(`challengeChunk${currentlyShowingChunkIndex}`).style.display = 'grid'; -// }); - -// log('AddEventListeners END'); -// }; diff --git a/src/scripts/modules/GetNextReset.js b/src/scripts/modules/GetNextReset.js new file mode 100644 index 0000000..d528f93 --- /dev/null +++ b/src/scripts/modules/GetNextReset.js @@ -0,0 +1,27 @@ + +// Find the next reset time, specific to the users timezone +export function getNextTuesday() { + let targetTime = '17:00:00 GMT+0100'; // 5 PM BST (bst is the baseline I am using) + let today = new Date(); + let daysUntilTuesday = (9 - today.getDay()) % 7; + let nextTuesday = new Date(today.getFullYear(), today.getMonth(), today.getDate() + daysUntilTuesday); + + let targetDate = new Date(`${nextTuesday.toDateString()} ${targetTime}`); + let targetTimestamp = targetDate.getTime(); + + let localOffset = new Date().getTimezoneOffset() * 60 * 1000; + let adjustedTimestamp = targetTimestamp - localOffset; + + let adjustedDate = new Date(adjustedTimestamp); + + if (adjustedDate < today) { + adjustedDate.setDate(adjustedDate.getDate() + 7); + }; + + let monthString = (adjustedDate.getMonth() + 1).toString().padStart(2, '0'); + let dateString = adjustedDate.getDate().toString().padStart(2, '0'); + let hoursString = adjustedDate.getHours().toString().padStart(2, '0'); + let minutesString = adjustedDate.getMinutes().toString().padStart(2, '0'); + + return `${monthString}/${dateString} ${hoursString}:${minutesString}`; +}; \ No newline at end of file diff --git a/src/scripts/modules/LoadCharacter.js b/src/scripts/modules/LoadCharacter.js index c822a3d..bc7a4a8 100644 --- a/src/scripts/modules/LoadCharacter.js +++ b/src/scripts/modules/LoadCharacter.js @@ -16,7 +16,9 @@ import { CacheChangeItem } from './CacheChangeItem.js'; import { AddTableRow } from './AddTableRow.js'; import { InsertSeperators } from './InsertSeperators.js'; import { StopLoad } from './StopLoad.js'; -import { ParseChar } from './ParseChar.js'; +import { ParseClass } from './ParseClass.js'; +import { ParseRace } from './ParseRace.js'; +import { MakeCharacterSelect } from './MakeCharacterSelect.js'; var characterLoadToggled = false, // Used to lockout character select during a load characterRecords; @@ -26,12 +28,13 @@ var seasonPassInfo = {}, seasonPassLevel = 0, prestigeProgressionSeasonInfo, seasonProgressionInfo = {}, - seasonalArtifactInfo = {}; + seasonalArtifactInfo = {}, + seasonInfo = {}; // Load character from specific index -// @int {classType}, @boolean {isRefresh} -export async function LoadCharacter(classType, characters) { +// @int {characterId}, @obj {characters}, @boolean {isFirstTimeLoad} +export async function LoadCharacter(characterId, characters, isFirstTimeLoad = true) { if (!characterLoadToggled) { @@ -49,71 +52,61 @@ export async function LoadCharacter(classType, characters) { CharacterInventories, CharacterObjectives, CharacterEquipment, - characterId, primaryCharacter, ItemSockets; // Clear (emtpy fields that are going to change) DOM content - document.getElementById('noItemsTooltip').style.display = 'none'; document.getElementById('bountyItems').innerHTML = ''; document.getElementById('overlays').innerHTML = ''; - document.getElementById('filters').innerHTML = ''; - document.getElementById('ctgDestination').innerHTML = 'There are no (specific) relations for destinations.'; - document.getElementById('ctgActivityMode').innerHTML = 'There are no (specific) relations for activities.'; - document.getElementById('ctgItemCategory').innerHTML = 'There are no (specific) relations for weapon types.'; - document.getElementById('ctgKillType').innerHTML = 'There are no (specific) relations for kill types.'; - - // Get chosen character via classType - for (let entry in UserProfile.characters) { - - let character = UserProfile.characters[entry]; - if (character.classType === classType) { - characterId = character.characterId; - primaryCharacter = character; + + // Get chosen character via characterId + for (let v in characters) { + + let char = characters[v]; + if (char.characterId === characterId) { + primaryCharacter = char; }; }; // Save character to localStorage CacheChangeItem('currentChar', primaryCharacter); - // Do character selects - document.getElementById('topCharacterTypeField').innerHTML = ParseChar(primaryCharacter.classType); - document.getElementById('topCharacterSelectImg').src = `https://www.bungie.net${primaryCharacter.emblemBackgroundPath}`; - document.getElementById('topCharacterPowerLevelField').innerHTML = primaryCharacter.light; - - let otherCharacters = Object.keys(characters).filter(v => v!==characterId); - for (let id of otherCharacters) { - - let char = characters[id]; - let emblemLargeBg = itemDefinitions[char.emblemHash].secondarySpecial; - let emblemPath = itemDefinitions[char.emblemHash].secondaryOverlay; - - if (!document.getElementById('middleCharacterTypeField').innerHTML) { - document.getElementById('middleCharacterTypeField').innerHTML = ParseChar(char.classType); - document.getElementById('middleCharacterContainer').style.backgroundImage = `url(https://www.bungie.net${emblemLargeBg})`; - document.getElementById('middleCharacterIconImg').src = `https://www.bungie.net${emblemPath}`; - document.getElementById('middleCharacterPowerLevelField').innerHTML = char.light; - } - else if (!document.getElementById('bottomCharacterTypeField').innerHTML) { - document.getElementById('bottomCharacterTypeField').innerHTML = ParseChar(char.classType); - document.getElementById('bottomCharacterContainer').style.backgroundImage = `url(https://www.bungie.net${emblemLargeBg})`; - document.getElementById('bottomCharacterIconImg').src = `https://www.bungie.net${emblemPath}`; - document.getElementById('bottomCharacterPowerLevelField').innerHTML = char.light; + // Check if first time load (build character selects if so etc) + if (isFirstTimeLoad) { + + // Make characterInfo object + let characterInfo = {}; + characterInfo.emblemIco = itemDefinitions[primaryCharacter.emblemHash].secondaryOverlay; + characterInfo.characterClass = ParseClass(primaryCharacter.classType); + characterInfo.characterRace = ParseRace(primaryCharacter.raceType); + characterInfo.characterPower = primaryCharacter.light; + characterInfo.characterId = primaryCharacter.characterId; + + // Add main character to DOM + MakeCharacterSelect(characterInfo); + + // Filter out character that is the main one + let otherCharacters = Object.keys(characters).filter(v => v!==characterId); + + // Add other characters to DOM + for (let id of otherCharacters) { + + // Make characterInfo obj for each character + let character = characters[id]; + let characterInfo = {}; + characterInfo.emblemIco = itemDefinitions[character.emblemHash].secondaryOverlay; + characterInfo.characterClass = ParseClass(character.classType); + characterInfo.characterRace = ParseRace(character.raceType); + characterInfo.characterPower = character.light; + characterInfo.characterId = character.characterId; + + // Add character to DOM + MakeCharacterSelect(characterInfo); }; }; - - // Hide containers dependant on how many characters a user has (1, 2 or 3) - if (otherCharacters.length === 0) { - document.getElementById('middleCharacterContainer').style.display = 'none'; - document.getElementById('bottomCharacterContainer').style.display = 'none'; - } - else if (otherCharacters.length === 1) { - document.getElementById('bottomCharacterContainer').style.display = 'none'; - }; // Get character-specific data from destinyUserProfile cache - log(UserProfile); CharacterProgressions = UserProfile.destinyUserProfile.characterProgressions.data[characterId].progressions; CharacterEquipment = UserProfile.destinyUserProfile.characterEquipment.data[characterId].items; CharacterObjectives = UserProfile.destinyUserProfile.itemComponents.objectives.data; @@ -154,17 +147,60 @@ export async function LoadCharacter(classType, characters) { }; }); - // Get season pass info - seasonProgressionInfo = CharacterProgressions[seasonDefinitions[UserProfile.CurrentSeasonHash].seasonPassProgressionHash]; - seasonPassInfo = seasonPassDefinitions[seasonDefinitions[UserProfile.CurrentSeasonHash].seasonPassHash]; - prestigeProgressionSeasonInfo = CharacterProgressions[seasonPassInfo.prestigeProgressionHash]; - seasonPassLevel = await ReturnSeasonPassLevel(seasonProgressionInfo, prestigeProgressionSeasonInfo); - seasonalArtifactInfo = itemDefinitions[seasonDefinitions[UserProfile.CurrentSeasonHash].artifactItemHash]; - seasonalArtifactInfo.powerBonusProgression = progressionDefinitions[1656313730]; - let seasonPassRewardsTrack = progressionDefinitions[seasonPassInfo.rewardProgressionHash].rewardItems, rewardsTrack = {}; + // Loop over season from definitions to get the highest statistics across all seasons + let pastSeasonLevels = []; + for (let hash in seasonDefinitions) { + + // Check if season >= season 8 + if (seasonDefinitions[hash].seasonNumber >= 8) { + + let season = seasonDefinitions[hash]; + + // Get season pass hash + let seasonPassHash = season.seasonPassHash; + let seasonPass = seasonPassDefinitions[seasonPassHash]; + + // Get season pass normal and prestige progression hash + let seasonPassProgressionHash = season.seasonPassProgressionHash; + let seasonPassProgressionPrestigeHash = seasonPass.prestigeProgressionHash; + + // Get info from each progression + let seasonProgression = CharacterProgressions[seasonPassProgressionHash]; + let seasonProgressionPrestige = CharacterProgressions[seasonPassProgressionPrestigeHash]; + + // Push season level to array + pastSeasonLevels.push(await ReturnSeasonPassLevel(seasonProgression, seasonProgressionPrestige)); + + }; + + // Check if hash is the current season + if (hash == UserProfile.currentSeasonHash) { + + // Pull info from the current season + seasonProgressionInfo = CharacterProgressions[seasonDefinitions[hash].seasonPassProgressionHash]; + seasonPassInfo = seasonPassDefinitions[seasonDefinitions[hash].seasonPassHash]; + prestigeProgressionSeasonInfo = CharacterProgressions[seasonPassInfo.prestigeProgressionHash]; + seasonPassLevel = await ReturnSeasonPassLevel(seasonProgressionInfo, prestigeProgressionSeasonInfo); + seasonalArtifactInfo = itemDefinitions[seasonDefinitions[hash].artifactItemHash]; + seasonalArtifactInfo.powerBonusProgression = progressionDefinitions[1656313730]; + seasonInfo = seasonDefinitions[hash]; + + }; + }; + + // Store season start date + seasonProgressionInfo.startDate = seasonInfo.startDate; + + // Sort levels in descending order to get highest season pass level + pastSeasonLevels = pastSeasonLevels.sort((a,b) => b-a); + let highestSeasonPassLevel = pastSeasonLevels[0]; + let seasonPassLevelsTotal = pastSeasonLevels.reduce((a,b) => a+b, 0); + + // Re-structure season pass rewards into a cleaner array structure + let seasonPassRewardsTrack = progressionDefinitions[seasonPassInfo.rewardProgressionHash].rewardItems; + let rewardsTrack = {}; - // Iterate through rewards track and formalize into a clean(er) array structure seasonPassRewardsTrack.forEach(v => { if (!rewardsTrack[v.rewardedAtProgressionLevel]) { @@ -175,33 +211,33 @@ export async function LoadCharacter(classType, characters) { // Push subheading statistics - AddValueToElementInner('currentSeasonNameField', seasonPassInfo.displayProperties.name); + // AddValueToElementInner('currentSeasonNameField', seasonPassInfo.displayProperties.name); // Get artifact info -- check if profile has artifact - let artifact; - if (UserProfileProgressions.ProfileProgressions.seasonalArtifact) { - - // Change corresponding HTML elements to display stats - artifact = UserProfileProgressions.ProfileProgressions.seasonalArtifact; - - if (artifact.pointProgression.nextLevelAt - artifact.pointProgression.progressToNextLevel !== 0) { - AddValueToElementInner('artifactXpToNextUnlock', InsertSeperators(artifact.pointProgression.nextLevelAt - artifact.pointProgression.progressToNextLevel)); - } - else { - document.getElementById('artifactStatsSecondContainer').style.display = 'none'; - }; - - AddValueToElementInner('artifactStatsArtifactBonus', `+${artifact.powerBonus}`); - AddValueToElementInner('artifactXpToNextPowerBonus', InsertSeperators(artifact.powerBonusProgression.nextLevelAt - artifact.powerBonusProgression.progressToNextLevel)); - } - else if (!UserProfileProgressions.ProfileProgressions.seasonalArtifact) { - - // Change corresponding HTML elements to display stats - document.getElementById('artifactStatsFirstContainer').style.display = 'none'; - document.getElementById('artifactStatsSecondContainer').style.display = 'none'; - document.getElementById('artifactStatsThirdMetricContainer').style.display = 'none'; - document.getElementById('artifactStatsNoArtifactIsPresent').style.display = 'block'; - }; + // let artifact; + // if (UserProfileProgressions.ProfileProgressions.seasonalArtifact) { + + // // Change corresponding HTML elements to display stats + // artifact = UserProfileProgressions.ProfileProgressions.seasonalArtifact; + + // if (artifact.pointProgression.nextLevelAt - artifact.pointProgression.progressToNextLevel !== 0) { + // AddValueToElementInner('artifactXpToNextUnlock', InsertSeperators(artifact.pointProgression.nextLevelAt - artifact.pointProgression.progressToNextLevel)); + // } + // else { + // document.getElementById('artifactStatsSecondContainer').style.display = 'none'; + // }; + + // AddValueToElementInner('artifactStatsArtifactBonus', `+${artifact.powerBonus}`); + // AddValueToElementInner('artifactXpToNextPowerBonus', InsertSeperators(artifact.powerBonusProgression.nextLevelAt - artifact.powerBonusProgression.progressToNextLevel)); + // } + // else if (!UserProfileProgressions.ProfileProgressions.seasonalArtifact) { + + // // Change corresponding HTML elements to display stats + // document.getElementById('artifactStatsFirstContainer').style.display = 'none'; + // document.getElementById('artifactStatsSecondContainer').style.display = 'none'; + // document.getElementById('artifactStatsThirdMetricContainer').style.display = 'none'; + // document.getElementById('artifactStatsNoArtifactIsPresent').style.display = 'block'; + // }; // Get progressional items var progressionalItemsObj = await ParseProgressionalItems(CharacterObjectives, CharacterInventories, characterId, characterRecords, seasonProgressionInfo, prestigeProgressionSeasonInfo, rewardsTrack, ghostModBonusXp, seasonalArtifactInfo); @@ -209,38 +245,38 @@ export async function LoadCharacter(classType, characters) { // Get relations for progressional items var relations = await ParseProgressionalRelations(progressionalItemsObj); - // Clear table and declare table div - let table = document.getElementById('relationsTable'); - relationsTable.div = table; - relationsTable.ClearTable(); - // Populate relations objects in global relationsTable object relationsTable.relations.bounties = relations.bounties; relationsTable.relations.challenges = relations.challenges; relationsTable.relations.all = relations.all; + relationsTable.relations.averageRelationCount = relations.averageRelationCount; + + // Declare table div then build the table + relationsTable.div = document.getElementById('relationsTable'); + relationsTable.BuildTable(); // Append allRelations to table - for (let index in relations.all) { + // for (let index in relations.all) { - // Find the category that the relation corresponds to - let relation = relations.all[index]; - let category; - for (let item in progressionPropertyKeyValues) { - - // If relation is in category, store in category - if (progressionPropertyKeyValues[item].includes(ParsePropertyNameIntoWord(relation[0], true))) { - category = item; - }; - }; - - if (category) { - AddTableRow(table, [relation[0], ParsePropertyNameIntoWord(category), `${relation[1]}pts`]); - }; - }; + // // Find the category that the relation corresponds to + // let relation = relations.all[index]; + // let category; + // for (let item in progressionPropertyKeyValues) { + + // // If relation is in category, store in category + // if (progressionPropertyKeyValues[item].includes(ParsePropertyNameIntoWord(relation[0], true))) { + // category = item; + // }; + // }; + + // if (category) { + // AddTableRow(table, [relation[0], ParsePropertyNameIntoWord(category), `${relation[1]}pts`]); + // }; + // }; // Stop loading sequence - CacheChangeItem('lastChar', classType); + CacheChangeItem('lastChar', characterId); characterLoadToggled = false; StopLoad(); }; diff --git a/src/scripts/modules/LoadPrimaryCharacter.js b/src/scripts/modules/LoadPrimaryCharacter.js index 9a56506..fcc0902 100644 --- a/src/scripts/modules/LoadPrimaryCharacter.js +++ b/src/scripts/modules/LoadPrimaryCharacter.js @@ -1,47 +1,43 @@ import { LoadCharacter } from './LoadCharacter.js'; import { CacheChangeItem } from './CacheChangeItem.js'; import { CacheReturnItem } from './CacheReturnItem.js'; -import { ClearApplicationData } from '../oauth/ClearApplicationData.js'; -import { clientId } from '../user.js'; -import { GenerateRandomString } from './GenerateRandomString.js'; // Load first character on profile // @object {characters} export async function LoadPrimaryCharacter(characters) { - - CacheReturnItem('lastChar') - .then(async (data) => { - - // If no character is found, load first character in list - if (data === undefined) { - - let fallbackCharacter = characters[Object.keys(characters)[0]].classType; - CacheChangeItem('lastChar', fallbackCharacter); - await LoadCharacter(fallbackCharacter, characters); - return; - - // Get first character in list, otherwise loop through until we find one - // let fallbackCharacter = characters[Object.keys(characters)[0]].classType; - // let fallbackCharacter; - // if (characters[Object.keys(characters)[0]]) { - // fallbackCharacter = characters[Object.keys(characters)[0]].classType; - // CacheChangeItem('lastChar', fallbackCharacter); - // await LoadCharacter(fallbackCharacter, characters); - // return; - // } - // else { - // // Clear user data - // ClearApplicationData(); - - // // Make new state code and redirect to bungie.net - // const stateCode = GenerateRandomString(128); - // localStorage.setItem('stateCode', stateCode); - // window.location.href = `https://www.bungie.net/en/oauth/authorize?&client_id=${clientId}&response_type=code&state=${stateCode}&randomqueryparam=${GenerateRandomString(128)}`; - // }; - }; - await LoadCharacter(data, characters); - }) - .catch((error) => { - console.error(error); - }); + + // Make promise for asynchronousy + return new Promise(async (resolve, reject) => { + + // Returns characterId + CacheReturnItem('lastChar') + .then(async (characterId) => { + + // If character is false or characterId does not exist in current character list + if (!(!characterId in Object.keys(characters)) || characterId === undefined) { + + // Find the most recently played character + let charactersSortedByRecentlyPlayed = Object.entries(characters).sort((a,b) => new Date(a.dateLastPlayed) > new Date(b.dateLastPlayed)); + let fallbackCharacterId = charactersSortedByRecentlyPlayed[0][1].characterId; + + // Change localStorage references and load character + CacheChangeItem('lastChar', fallbackCharacterId); + await LoadCharacter(fallbackCharacterId, characters); + } + + // Else, load the last-stored character + else { + await LoadCharacter(characterId, characters); + }; + + // Resolve the promise + resolve(); + + }) + .catch((error) => { + console.error(error); + reject(error); + }); + + }); }; \ No newline at end of file diff --git a/src/scripts/modules/MakeBountyElement.js b/src/scripts/modules/MakeBountyElement.js index a32254f..db874bd 100644 --- a/src/scripts/modules/MakeBountyElement.js +++ b/src/scripts/modules/MakeBountyElement.js @@ -8,12 +8,13 @@ export async function MakeBountyElement(param) { let itemObjectivesContainer = document.createElement('div'); let itemOverlay = document.createElement('div'); let itemContainer = document.createElement('div'); + let itemHeader = document.createElement('div'); + let itemAttributes = document.createElement('div'); let itemStatus = document.createElement('img'); let itemTitle = document.createElement('div'); let itemType = document.createElement('div'); let itemDesc = document.createElement('div'); let item = document.createElement('img'); - let hr = document.createElement('hr'); // itemContainer style itemContainer.className = 'itemContainer'; @@ -38,24 +39,36 @@ export async function MakeBountyElement(param) { itemObjectivesContainer.className = 'itemObjectivesContainer'; // Prop content of item + itemHeader.className = 'itemHeader'; itemTitle.id = 'itemTitle'; itemType.id = 'itemType'; itemDesc.id = 'itemDesc'; + itemAttributes.className = 'itemAttributes'; itemTitle.innerHTML = param.displayProperties.name; itemType.innerHTML = param.itemTypeDisplayName; - itemDesc.innerHTML = param.displayProperties.description; + + // Reformat item description to include a breakline when a sentence ends + let itemDescriptionSplit = (param.displayProperties.description).split('.'); + itemDesc.innerHTML = `${itemDescriptionSplit[0]}.

${itemDescriptionSplit[1]}`; + // itemDesc.innerHTML = itemDescriptionSplit[0] + '.' + '
' + itemDescriptionSplit[1]; // Assign content to parent - document.querySelector(`#item_${param.hash}`).append(itemTitle, itemType, hr, itemDesc); + itemHeader.append(itemTitle, itemType); + document.querySelector(`#item_${param.hash}`).append(itemHeader); // Create item progress and push to DOM - let rootIndex = param.objectiveDefinitions, completionCounter = 0; + let rootIndex = param.objectiveDefinitions; + let completionCounter = 0; for (let indexCount = 0; indexCount < rootIndex.length; indexCount++) { - let itemPrgContainer = document.createElement('div'); - let itemPrgCounter = document.createElement('div'); + let itemPrgCounter = document.createElement('div'); let itemPrgDesc = document.createElement('div'); + let objectiveContainer = document.createElement('div'); + let objectiveCheckbox = document.createElement('div'); + let objectiveCheckboxOuter = document.createElement('div'); + let objectiveCheckboxMiddle = document.createElement('div'); + let objectiveCheckboxInner = document.createElement('div'); // Check if progess string exceeds char limit if (rootIndex[indexCount].progressDescription.length >= 24) { @@ -67,33 +80,51 @@ export async function MakeBountyElement(param) { rootIndex[indexCount].progressDescription = rt + '..'; }; - itemPrgContainer.className = 'itemPrgContainer'; + // Give item progress attributes their style itemPrgCounter.className = 'itemPrgCounter'; itemPrgDesc.className = 'itemPrgDesc'; itemPrgCounter.id = `prgCounter_${rootIndex[indexCount].hash}`; itemPrgDesc.id = `prgDesc_${rootIndex[indexCount].hash}`; - itemPrgContainer.appendChild(itemPrgDesc); - itemPrgContainer.appendChild(itemPrgCounter); - itemObjectivesContainer.appendChild(itemPrgContainer); - document.querySelector(`#item_${param.hash}`).appendChild(itemObjectivesContainer); + // Create objective checkboxes + objectiveContainer.className = 'objectiveContainer'; + objectiveCheckboxOuter.className = 'objectiveCheckboxOuter'; + objectiveCheckboxOuter.id = `Outer_${rootIndex[indexCount].hash}`; + objectiveCheckboxMiddle.className = 'objectiveCheckboxMiddle'; + objectiveCheckboxMiddle.id = `Middle_${rootIndex[indexCount].hash}`; + objectiveCheckboxInner.className = 'objectiveCheckboxInner'; + objectiveCheckboxInner.id = `Inner_${rootIndex[indexCount].hash}`; + objectiveCheckboxOuter.appendChild(objectiveCheckboxMiddle); + objectiveCheckboxMiddle.appendChild(objectiveCheckboxInner); + objectiveCheckbox.appendChild(objectiveCheckboxOuter); + + // Add checkbox and item progress to flex container + objectiveContainer.append(objectiveCheckbox, itemPrgDesc, itemPrgCounter); + itemObjectivesContainer.append(objectiveContainer); + + itemAttributes.appendChild(itemDesc); + itemAttributes.appendChild(itemObjectivesContainer); + document.querySelector(`#item_${param.hash}`).appendChild(itemAttributes); // Render item objective progress itemPrgDesc.innerHTML = rootIndex[indexCount].progressDescription; - param.progress.forEach(h => { - if (h.objectiveHash === rootIndex[indexCount].hash) { + param.progress.forEach(v => { + if (v.objectiveHash === rootIndex[indexCount].hash) { // Render objective progress if (rootIndex[indexCount].completionValue === 100) { - itemPrgCounter.innerHTML = `${h.progress}%`; + itemPrgCounter.innerHTML = `${v.progress}%`; } else if (rootIndex[indexCount].completionValue !== 100) { - itemPrgCounter.innerHTML = `${h.progress}/${h.completionValue}`; + itemPrgCounter.innerHTML = `${v.progress}/${v.completionValue}`; }; // Check if objective is completed - if (h.complete) { + if (v.complete) { completionCounter++; + document.getElementById(`Outer_${v.objectiveHash}`).style.border = '1.5px solid var(--completedCheckboxOuter)'; + document.getElementById(`Middle_${v.objectiveHash}`).style.border = '1.5px solid var(--completedCheckboxMiddle)'; + document.getElementById(`Inner_${v.objectiveHash}`).style.backgroundColor = 'var(--completedCheckboxInner)'; }; }; }); @@ -103,6 +134,7 @@ export async function MakeBountyElement(param) { if (param.progress.length === completionCounter) { // Change areObjectivesComplete boolean param.areObjectivesComplete = true; + } else if (param.progress.length !== completionCounter) { // Change areObjectivesComplete boolean @@ -113,46 +145,28 @@ export async function MakeBountyElement(param) { if (param.isExpired && !param.areObjectivesComplete) { itemStatus.classList += ` expire`; itemStatus.id = `expire_${param.hash}`; - itemStatus.src = './static/ico/pursuit_expired.svg'; + itemStatus.src = './static/ico/destiny-icons/pursuit_expired.svg'; document.getElementById(`bounty_${param.hash}`).style.border = '1px solid rgba(179,73,73, 0.749)'; } else if (param.areObjectivesComplete) { itemStatus.classList += ` complete`; itemStatus.id = `complete_${param.hash}`; - itemStatus.src = './static/ico/pursuit_completed.svg'; + itemStatus.src = './static/ico/destiny-icons/pursuit_completed.svg'; document.getElementById(`bounty_${param.hash}`).style.border = '1px solid rgba(182,137,67, 0.749)'; }; // Append the item status to the item itemContainer.appendChild(itemStatus); - // document.querySelector(`#bountyItems`).append(itemStatus); - // Watch for mouse events + // Watch for mouse move event (when mouse hovers over bounty element) itemContainer.addEventListener('mousemove', function (e) { itemOverlay.style.position = 'absolute'; itemOverlay.style.display = 'block'; - // let itemOverlayPos = parseInt(itemOverlay.style.left.split('px')[0]); - // let itemOverlayWidth = 210; - itemOverlay.style.left = `${e.pageX}px`; itemOverlay.style.top = `${e.pageY}px`; - // if (((window.innerWidth - itemOverlayWidth) >= itemOverlayPos)) { - // // console.log(((window.innerWidth - itemOverlayWidth) >= itemOverlayPos)); - // itemOverlay.style.left = `${e.pageX}px`; - // itemOverlay.style.top = `${e.pageY}px`; - // return; - // }; - - // if (!((window.innerWidth - itemOverlayWidth) >= itemOverlayPos)) { - // // console.log(((window.innerWidth - itemOverlayWidth) >= itemOverlayPos)); - // itemOverlay.style.left = `${window.innerWidth - (itemOverlayWidth + 10)}px`; - // itemOverlay.style.top = `${e.pageY}px`; - // return; - // }; - }); itemContainer.addEventListener('mouseleave', (e) => { diff --git a/src/scripts/modules/MakeCharacterSelect.js b/src/scripts/modules/MakeCharacterSelect.js new file mode 100644 index 0000000..6cfcc50 --- /dev/null +++ b/src/scripts/modules/MakeCharacterSelect.js @@ -0,0 +1,76 @@ + +// Make a character select that is displayed on the top left +// @object {info} +export function MakeCharacterSelect (info) { + + // Make div elements + let characterSelect = document.createElement('div'); + let characterBg = document.createElement('div'); + let characterClassIco = document.createElement('img'); + let characterEmblemIco = document.createElement('img'); + let characterInfo = document.createElement('div'); + let characterClass = document.createElement('div'); + let characterRace = document.createElement('div'); + let characterPowerCon = document.createElement('div'); + let powerIcon = document.createElement('img'); + let characterPower = document.createElement('div'); + + // Add css classes (style) to div elements + characterSelect.className = 'characterSelect'; + characterBg.className = 'characterBg'; + characterClassIco.className = 'characterClassIco'; + characterEmblemIco.className = 'characterEmblemIco'; + characterInfo.className = 'characterInfo'; + characterClass.className = 'characterClass'; + characterRace.className = 'characterRace'; + characterPowerCon.className = 'characterPowerCon'; + powerIcon.className = 'powerIcon'; + characterPower.className = 'characterPower'; + + // Add hierarchy to div elements + characterBg.appendChild(characterClassIco); + characterSelect.appendChild(characterBg); + characterSelect.appendChild(characterEmblemIco); + characterInfo.appendChild(characterClass); + characterInfo.appendChild(characterRace); + characterSelect.appendChild(characterInfo); + characterPowerCon.appendChild(powerIcon); + characterPowerCon.appendChild(characterPower); + characterSelect.appendChild(characterPowerCon); + + // Add values (and data attr) to corresponding div elements + characterEmblemIco.src = `https://www.bungie.net${info.emblemIco}`; + characterClass.innerHTML = info.characterClass; + characterRace.innerHTML = info.characterRace; + characterPower.innerHTML = info.characterPower; + characterSelect.dataset.characterId = info.characterId; + powerIcon.src = 'static/ico/destiny-icons/power2.svg'; + + // Check character class and change div elements + if (info.characterClass === 'Titan') { + + characterClassIco.src = 'static/ico/destiny-icons/class_titan.svg'; + characterClassIco.style.filter = 'invert(21%) sepia(47%) saturate(1408%) hue-rotate(317deg) brightness(100%) contrast(90%)'; + characterBg.style.background = 'linear-gradient(90deg,#89323800 50%,#89323866)'; + } + else if (info.characterClass === 'Warlock') { + + // Warlock requires some custom styling + characterClassIco.src = 'static/ico/destiny-icons/class_warlock.svg'; + characterClassIco.style.filter = 'invert(63%) sepia(26%) saturate(1130%) hue-rotate(6deg) brightness(87%) contrast(87%)'; + characterClassIco.style.marginTop = '-30px'; + characterClassIco.style.marginRight = '27px'; + characterClassIco.style.width = '50%'; + characterBg.style.background = 'linear-gradient(90deg,#b68f2800 50%,#b68f2866)'; + } + else if (info.characterClass === 'Hunter') { + + characterClassIco.src = 'static/ico/destiny-icons/class_hunter.svg'; + characterClassIco.style.filter = 'invert(50%) sepia(44%) saturate(267%) hue-rotate(144deg) brightness(87%) contrast(85%)'; + characterBg.style.background = 'linear-gradient(90deg,#5c828b00 50%,#5c828b66)'; + }; + + // Add parent element to DOM (defaultCharacterSelect) + document.getElementById('defaultCharacterSelect').appendChild(characterSelect); + +}; diff --git a/src/scripts/modules/ModuleScript.js b/src/scripts/modules/ModuleScript.js index 0cfcd79..5f2b988 100644 --- a/src/scripts/modules/ModuleScript.js +++ b/src/scripts/modules/ModuleScript.js @@ -1,3 +1,10 @@ + +/* + + None of these functions are used so they are marked as deprecated, for now. + +*/ + import { itemTypeKeys } from "./SynergyDefinitions.js"; import { allProgressionProperties, UserProfile, log } from "../user.js"; import { LoadCharacter } from './LoadCharacter.js'; diff --git a/src/scripts/modules/ParseBounties.js b/src/scripts/modules/ParseBounties.js index a124fef..cacc0b9 100644 --- a/src/scripts/modules/ParseBounties.js +++ b/src/scripts/modules/ParseBounties.js @@ -1,5 +1,5 @@ -import { excludedBountiesByVendor } from '../user.js'; -import { VendorHashesByLabel } from './SynergyDefinitions.js'; +import { excludedBountiesByVendor, log } from '../user.js'; +import { VendorHashesByLabel, progressionItemGroupTypes } from './SynergyDefinitions.js'; import { stringMatchProgressionItem } from './StringMatchProgressionItem.js'; import { ReplaceStringVariables } from './ReplaceStringVariables.js'; @@ -60,6 +60,43 @@ export function ParseBounties(charInventory, charObjectives, itemDefinitions) { item.isComplete = true; }; + /* + Set isRepeatable to false if the stackUniqueLabel includes 'repeatable' + This won't work correctly as stackUniqueLabel has no standardized format that it follows + + Repeatable bounties almost always state the *group type via the itemTypeDisplayName. + *Group type (crucible, gunsmith, vanguard, etc) + Daily bounties almost always state the group type via the displayProperties.description + This is why we are making this check to ensure the item has its group type present in props + + // Pending on deletion or refactor/re-use + */ + if (item.inventory.stackUniqueLabel.includes('repeatable')) { + + // Add bounty group type to item.props + item.isRepetable = true; + // item.props.push(item.itemTypeDisplayName.split(' ')[0]); + } + else { + + item.isRepetable = false; + + // // Add bounty group type to item.props + // let itemGroupTypes = progressionItemGroupTypes.map(v => v.toLowerCase()); + // let stackUniqueLabel = item.inventory.stackUniqueLabel.split('.'); + // let groupTypeProps = []; + + // itemGroupTypes.forEach(v => { + // if (stackUniqueLabel.includes(v)) { + // groupTypeProps.push(v); + // }; + // }); + + // if (groupTypeProps.length > 0) { + // item.props.push(groupTypeProps); + // }; + }; + // Push bounty item to charBounties and increment amountOfBounties charBounties.push(item); amountOfBounties++; diff --git a/src/scripts/modules/ParseChar.js b/src/scripts/modules/ParseChar.js deleted file mode 100644 index 6dcf779..0000000 --- a/src/scripts/modules/ParseChar.js +++ /dev/null @@ -1,24 +0,0 @@ - -// Returns corresponding class name string using classType or vice versa -// @int {classType} @bool {isReverse} -export function ParseChar(classType, isReverse = false) { - - if (classType === 0 || classType === 'Titan') { - if (!isReverse) { - return 'Titan'; - }; - return 0; - } - else if (classType === 1 || classType === 'Hunter') { - if (!isReverse) { - return 'Hunter'; - }; - return 1; - } - else if (classType === 2 || classType === 'Warlock') { - if (!isReverse) { - return 'Warlock'; - }; - return 2; - }; -}; \ No newline at end of file diff --git a/src/scripts/modules/ParseClass.js b/src/scripts/modules/ParseClass.js new file mode 100644 index 0000000..40a76da --- /dev/null +++ b/src/scripts/modules/ParseClass.js @@ -0,0 +1,27 @@ + +// Returns corresponding class name string using classType or vice versa +// @int {classType} @bool {isReverse} +export function ParseClass(classType, isReverse = false) { + + // If isReverse then we are turning the string version of the class, back into its number form + if (isReverse) { + switch (classType) { + case 'Titan': + return 0; + case 'Hunter': + return 1; + case 'Warlock': + return 2; + }; + }; + + // Return corresponding string + switch (classType) { + case 0: + return 'Titan'; + case 1: + return 'Hunter'; + case 2: + return 'Warlock'; + }; +}; \ No newline at end of file diff --git a/src/scripts/modules/ParseProgressItems.js b/src/scripts/modules/ParseProgressItems.js index 561a9c4..0a0ca46 100644 --- a/src/scripts/modules/ParseProgressItems.js +++ b/src/scripts/modules/ParseProgressItems.js @@ -10,7 +10,8 @@ import { itemDefinitions, objectiveDefinitions, UserProfileProgressions, - progressionDefinitions} from '../user.js'; + progressionDefinitions, + UserProfile } from '../user.js'; import { MakeBountyElement } from './MakeBountyElement.js'; import { ParseSeasonalChallenges } from './ParseSeasonalChallenges.js'; import { ReturnSeasonPassProgressionStats } from './ReturnSeasonPassProgressionStats.js'; @@ -62,14 +63,18 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve document.getElementById('ghostModsCheckmarkIcon').style.filter = filterToResetCheckmark; // Get all seasonal challenges - let allSeasonalChallenges = await ParseSeasonalChallenges(2809059433, seasonDefinitions, recordDefinitions, presentationNodeDefinitions, null); - returnObj.challenges = allSeasonalChallenges; // Add to return object + let currentSeasonalChallenges = await ParseSeasonalChallenges(UserProfile.currentSeasonHash, seasonProgressionInfo); + returnObj.challenges = currentSeasonalChallenges; // Add to return object - // Parse seasonal challenges into corresponding objects - let completedChallenges = {}, - notCompletedChallenges = {}, - allSeasonalChallengesAndTheirDivs = {}; + // Separate challenges based on their completion status + let completedChallenges = {}; + let notCompletedChallenges = {}; + let allSeasonalChallengesAndTheirDivs = {}; + let completedChallengesCount = 0; + let notCompletedChallengesCount = 0; + + // Add objectives to (all) seasonal challenges for (const recordHash in characterRecords) { const objectives = characterRecords[recordHash].objectives; @@ -88,59 +93,80 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve }; }; - // Create HTML elements for seasonal challenges - for (const challengeHash in allSeasonalChallenges) { + for (let challengeHash in currentSeasonalChallenges) { // Create HTML element for challenge - let challengeContainer = document.createElement('div'), - challengeIcon = document.createElement('img'), - challengeName = document.createElement('div'), - challengeBreakline = document.createElement('hr'), - challengeDescription = document.createElement('div'), - challengeProgressContainer = document.createElement('div'), - challengeProgressTrack = document.createElement('div'), - challengeProgressPercentBar = document.createElement('div'); + let challengeContainer = document.createElement('div'); + let challengeHeadingContainer = document.createElement('div'); + let challengeHeadingAttributeContainer = document.createElement('div'); + let challengeIcon = document.createElement('img'); + let challengeName = document.createElement('div'); + let challengeDescription = document.createElement('div'); + let challengeProgressContainer = document.createElement('div'); + let challengeProgressTrack = document.createElement('div'); + let challengeProgressPercentBar = document.createElement('div'); + let challengeRewardsContainer = document.createElement('div'); + let challengeProgressAttributesContainer = document.createElement('div'); // Set attributes for challenge container challengeContainer.className = 'challengeContainer'; + challengeHeadingContainer.className = 'challengeHeadingContainer'; + challengeHeadingAttributeContainer.className = 'challengeHeadingAttributeContainer'; challengeContainer.id = `${challengeHash}`; challengeIcon.className = 'challengeIcon'; challengeName.className = 'challengeName'; - challengeBreakline.className = 'challengeBreakline'; challengeDescription.className = 'challengeDescription'; challengeProgressContainer.className = 'challengeProgressContainer'; challengeProgressTrack.className = 'challengeProgressTrack'; challengeProgressPercentBar.className = 'challengeProgressPercentBar'; + challengeRewardsContainer.className = 'challengeRewardsContainer'; + challengeProgressAttributesContainer.className = 'challengeProgressAttributesContainer'; // Set attributes for content - challengeDescription.innerHTML = allSeasonalChallenges[challengeHash].displayProperties.description; - challengeName.innerHTML = allSeasonalChallenges[challengeHash].displayProperties.name; - challengeIcon.src = `https://www.bungie.net${allSeasonalChallenges[challengeHash].displayProperties.icon}`; + challengeDescription.innerHTML = currentSeasonalChallenges[challengeHash].displayProperties.description; + challengeName.innerHTML = currentSeasonalChallenges[challengeHash].displayProperties.name; + challengeIcon.src = `https://www.bungie.net${currentSeasonalChallenges[challengeHash].displayProperties.icon}`; challengeContainer.style.userSelect = 'none'; // Check if challenge is completed if (completedChallenges[challengeHash]) { - challengeContainer.style.border = '1px solid #b39a36'; + + challengeContainer.classList.add('challengeContainerComplete'); + currentSeasonalChallenges[challengeHash].isComplete = true; + + // Check if challenge has been claimed + let destinyProfileRecords = UserProfile.destinyUserProfile.characterRecords.data[characterId].records; + if (destinyProfileRecords[challengeHash]) { + + if (destinyProfileRecords[challengeHash].state === 0) { + currentSeasonalChallenges[challengeHash].isClaimed = false; + challengeContainer.classList.remove('challengeContainerComplete'); + challengeContainer.classList.add('challengeContainerCompletedNotClaimed'); + } + else if (destinyProfileRecords[challengeHash].state === 1) { + currentSeasonalChallenges[challengeHash].isClaimed = true; + }; + }; + + } + else { + challengeContainer.classList.add('challengeContainerNotComplete'); + currentSeasonalChallenges[challengeHash].isComplete = false; }; // Append all the content together - challengeProgressContainer.appendChild(challengeProgressTrack); - challengeProgressContainer.appendChild(challengeProgressPercentBar); - challengeContainer.appendChild(challengeIcon); - challengeContainer.appendChild(challengeName); - challengeContainer.appendChild(challengeBreakline); - challengeContainer.appendChild(challengeDescription); - challengeContainer.appendChild(challengeProgressContainer); + challengeHeadingContainer.append(challengeIcon, challengeHeadingAttributeContainer); + challengeHeadingAttributeContainer.append(challengeName, challengeDescription); + challengeContainer.appendChild(challengeHeadingContainer); // Store the challenge and its div allSeasonalChallengesAndTheirDivs[challengeHash] = {}; allSeasonalChallengesAndTheirDivs[challengeHash].container = challengeContainer; - allSeasonalChallengesAndTheirDivs[challengeHash].challenge = allSeasonalChallenges[challengeHash]; + allSeasonalChallengesAndTheirDivs[challengeHash].challenge = currentSeasonalChallenges[challengeHash]; // Append objectives to the challenge allSeasonalChallengesAndTheirDivs[challengeHash].challenge.objectives = []; - if (notCompletedChallenges[challengeHash] || completedChallenges[challengeHash]) { let challengeObjectives; @@ -149,7 +175,7 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve if (Object.keys(notCompletedChallenges).includes(challengeHash)) { challengeObjectives = notCompletedChallenges[challengeHash].objectives; - for (const objective in challengeObjectives) { + for (let objective in challengeObjectives) { allSeasonalChallengesAndTheirDivs[challengeHash].challenge.objectives.push(notCompletedChallenges[challengeHash].objectives[objective]); }; }; @@ -158,31 +184,120 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve if (Object.keys(completedChallenges).includes(challengeHash)) { challengeObjectives = completedChallenges[challengeHash].objectives; - for (const objective in challengeObjectives) { + for (let objective in challengeObjectives) { allSeasonalChallengesAndTheirDivs[challengeHash].challenge.objectives.push(completedChallenges[challengeHash].objectives[objective]); }; }; }; + // Add objective element to challenge + for (let objective of currentSeasonalChallenges[challengeHash].objectives) { + + // Objective container + let objectiveContainer = document.createElement('div'); + + // Checkbox + let objectiveCheckboxOuter = document.createElement('div'); + let objectiveCheckboxMiddle = document.createElement('div'); + let objectiveCheckboxInner = document.createElement('div'); + + // Checkbox style + objectiveCheckboxOuter.className = 'objectiveCheckboxOuter'; + objectiveCheckboxMiddle.className = 'objectiveCheckboxMiddle'; + objectiveCheckboxInner.className = 'objectiveCheckboxInner'; + + // Progress bar (objectiveAttributes doubles as a container) + let objectiveAttributes = document.createElement('div'); + let objectiveName = document.createElement('div'); + let objectiveProgress = document.createElement('div'); + + // Progress bar style + objectiveAttributes.className = 'objectiveAttributes'; + objectiveContainer.className = 'objectiveContainer'; + objectiveName.className = 'objectiveName'; + objectiveProgress.className = 'objectiveProgress'; + + // InnerHTML values etc + objectiveName.innerHTML = objectiveDefinitions[objective.objectiveHash].progressDescription || 'Completed'; + objectiveProgress.innerHTML = `${objective.progress}/${objective.completionValue}`; + + // If objective is complete + if (objective.complete) { + + // Change innerHTML to avoid overflow values + objectiveProgress.innerHTML = `${objective.completionValue}/${objective.completionValue}`; + + // Change checkbox style + objectiveCheckboxOuter.style.borderColor = 'var(--challengeCompletedCheckboxOuter)'; + objectiveCheckboxMiddle.style.borderColor = 'var(--challengeCompletedCheckboxMiddle)'; + objectiveCheckboxInner.style.backgroundColor = 'var(--challengeCompletedCheckboxInner)'; + + // Change attribute container style (to children too) + objectiveName.style.color = '#BABABA'; + objectiveProgress.style.color = '#BABABA'; + objectiveAttributes.style.color = '#494949'; + }; + + // Append elements to their parents + objectiveCheckboxOuter.appendChild(objectiveCheckboxMiddle); + objectiveCheckboxMiddle.appendChild(objectiveCheckboxInner); + objectiveAttributes.append(objectiveName, objectiveProgress); + + // Push elements to top-most parent + objectiveContainer.append(objectiveCheckboxOuter, objectiveAttributes); + + // Push objectives to parent container + challengeProgressAttributesContainer.appendChild(objectiveContainer); + + }; + challengeContainer.appendChild(challengeProgressAttributesContainer); + + // Add reward items to the challenge + if (currentSeasonalChallenges[challengeHash].rewardItems) { + + let challengeRewardItems = currentSeasonalChallenges[challengeHash].rewardItems; + for (let reward of challengeRewardItems) { + + let rewardContainer = document.createElement('div'); + let rewardName = document.createElement('div'); + let rewardIcon = document.createElement('img'); + + rewardContainer.className = 'singleChallengeRewardContainer'; + rewardName.innerHTML = itemDefinitions[reward.itemHash].displayProperties.name; + rewardIcon.src = `https://www.bungie.net${itemDefinitions[reward.itemHash].displayProperties.icon}`; + rewardName.className = 'challengeRewardName'; + rewardIcon.className = 'challengeRewardIcon'; + + rewardContainer.append(rewardIcon, rewardName); + challengeRewardsContainer.appendChild(rewardContainer); + }; + + challengeContainer.appendChild(challengeRewardsContainer); + }; + // Check if the challenge is completed, set isComplete to true in guard statement, otherwise false by default // This is to make it easier to check if the challenge is complete, as opposed to comparing with completedChallenges - allSeasonalChallengesAndTheirDivs[challengeHash].challenge.isComplete = false; if (completedChallenges[challengeHash]) { + completedChallengesCount++; allSeasonalChallengesAndTheirDivs[challengeHash].challenge.isComplete = true; + } + else { + notCompletedChallengesCount++; + allSeasonalChallengesAndTheirDivs[challengeHash].challenge.isComplete = false; }; // Sort challenge completion progress as a percentage of the total completion value - let challengeObjectiveProgressTotal = 0, - challengeObjectiveCompletionTotal = 0, - challengeObjectives = allSeasonalChallengesAndTheirDivs[challengeHash].challenge.objectives; + let challengeObjectiveProgressTotal = 0; + let challengeObjectiveCompletionTotal = 0; + let challengeObjectives = allSeasonalChallengesAndTheirDivs[challengeHash].challenge.objectives; - for (const objective of challengeObjectives) { - challengeObjectiveProgressTotal += objective.progress; - challengeObjectiveCompletionTotal += objective.completionValue; + for (const objective in challengeObjectives) { + challengeObjectiveProgressTotal += challengeObjectives[objective].progress; + challengeObjectiveCompletionTotal += challengeObjectives[objective].completionValue; }; - // Calculate progress as a percentage, if objective is "0/1" then it is a boolean, - // so set progress to 0% (if not complete) or 100% (if complete) + // Calculate progress as a percentage, if objective is "0/1" then it is a boolean, + // so set progress (if not complete) or 100% (if complete, avoid overflow) allSeasonalChallengesAndTheirDivs[challengeHash].challenge.completionPercentage = (challengeObjectiveProgressTotal / challengeObjectiveCompletionTotal) * 100; // Change width of challengeProgressPercentBar based on completion percentage @@ -192,46 +307,63 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve else { challengeProgressPercentBar.style.width = `${allSeasonalChallengesAndTheirDivs[challengeHash].challenge.completionPercentage}%`; }; + }; - // Sort challenges by completion percentage, in ascending order + + // Sort challenges by completion percentage, in ascending order (so the completed ones are at the end) let sortedChallenges = Object.values(allSeasonalChallengesAndTheirDivs).sort((a, b) => a.challenge.completionPercentage - b.challenge.completionPercentage); - // Slice the array of challenges into chunks of 6 - let chunkedChallenges = []; - for (let i=0; i v.challenge)); + + // Find out how many "chunks" we need to display all the challenges + let chunkCount = sortedChallenges.length / 6; + + // If there is a remainder + if (chunkCount % 1 !== 0) { + + // Add one and truncate number (account for overflow) + chunkCount++; + chunkCount = Math.trunc(chunkCount); }; - // Create HTML elements for each chunk of challenges - for (let i=0; i { + + let group = bountyArr[v]; + if (group.length !== 0) { + group.forEach(item => { + newBountyArr.push(item); + }); + }; + }); + + // Sort bounties by completion status + newBountyArr.sort((a,b) => { + if (a.isComplete === b.isComplete) { + return 0; + } + else { + if (a.isComplete) { + return -1; + } + else { + return 1; + }; + }; + }); + newBountyArr.reverse(); + + // Push items to DOM + newBountyArr.forEach(item => MakeBountyElement(item)); + // Get statistics for subheadings - let amountOfExpiredBounties = 0, - amountOfCompletedBounties = 0; + let amountOfExpiredBounties = 0; + let amountOfCompletedBounties = 0; // Count completed and expired bounties for (let bounty of characterBounties) { @@ -298,7 +461,7 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve }; }; - // Get weekly progress + // Get weekly progress -- If player is >= level 100 then it means they have "prestiged" let weeklyProgress; if (seasonPassProgressionStats.seasonPassLevel >= 100) { weeklyProgress = prestigeProgressionSeasonInfo.weeklyProgress; @@ -375,11 +538,6 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve let artifact = UserProfileProgressions.ProfileProgressions.seasonalArtifact; let artifactPointProgressionDefinition = progressionDefinitions[artifact.pointProgression.progressionHash]; let artifactPowerBonusDefinition = progressionDefinitions[artifact.powerBonusProgression.progressionHash]; - log(artifact); - - let nextLevelAt = artifact.powerBonusProgression.nextLevelAt; - let percentage = totalXpYieldWithModifiers / nextLevelAt; - log(percentage); /* @@ -390,6 +548,8 @@ export async function ParseProgressionalItems(CharacterObjectives, CharacterInve */ + // .. + // Check if there are no bounties if (amountOfBounties === 0) { diff --git a/src/scripts/modules/ParseProgressRelations.js b/src/scripts/modules/ParseProgressRelations.js index ea34a97..5ba43f2 100644 --- a/src/scripts/modules/ParseProgressRelations.js +++ b/src/scripts/modules/ParseProgressRelations.js @@ -1,9 +1,10 @@ - +import { log } from '../user.js'; +import { progressionItemGroupTypes } from './SynergyDefinitions.js'; // Function to find all the relations between progressional items // @obj {progressionalItems} export async function ParseProgressionalRelations(progressionalItems) { - + let bountyRelations = {}, challengeRelations = {}, allRelations = {}; @@ -11,60 +12,157 @@ export async function ParseProgressionalRelations(progressionalItems) { // Used to find percentage let relationCount = 0; + // // Increment the relation every time there is another bounty that has the same prop + // for (let firstBounty of progressionalItems.charBounties) { + // for (let secondBounty of progressionalItems.charBounties) { + // if (firstBounty.hash !== secondBounty.hash) { + + // let groupFirstBounty; + // let groupSecondBounty; + + // // Find group for both bounties + // progressionItemGroupTypes.forEach(group => { + + // if (firstBounty.props.includes(group)) { + // groupFirstBounty = group; + // }; + + // if (secondBounty.props.includes(group)) { + // groupSecondBounty = group; + // }; + + // }); + + // if (groupFirstBounty !== undefined && groupSecondBounty !== undefined && groupFirstBounty === groupSecondBounty) { + // log(groupFirstBounty, groupSecondBounty); + // }; + + // // .. + // if (groupFirstBounty === groupSecondBounty) { + + // firstBounty.props.forEach(v => { + // if (!bountyRelations[v]) { + // bountyRelations[v] = 1; + // } + // else { + // bountyRelations[v]++; + // }; + // }); + + // secondBounty.props.forEach(z => { + // if (!bountyRelations[z]) { + // bountyRelations[z] = 1; + // } + // else { + // bountyRelations[z]++; + // }; + // }); + + // relationCount++; + // }; + + // }; + // }; + // }; + // Loop through character bounties for (let bounty of progressionalItems.charBounties) { - - // Loop through props and add to bountyRelations - bounty.props.forEach((prop) => { - - // Check if prop exists in bountyRelations, if so add 1 - if (bountyRelations[prop]) { - bountyRelations[prop]++; - } - else { // if not create it - bountyRelations[prop] = 1; - }; - relationCount++; - }); + + // Check if bounty is incomplete before adding relation + if (!bounty.isComplete) { + + // Loop through props and add to bountyRelations + bounty.props.forEach((prop) => { + + // Check if prop exists in bountyRelations, if so add 1 + if (bountyRelations[prop]) { + bountyRelations[prop]++; + } + else { // if not create it + bountyRelations[prop] = 1; + }; + relationCount++; + }); + }; }; // Loop through challenges for (let index in progressionalItems.challenges) { - // Loop through challenge props let challenge = progressionalItems.challenges[index]; - challenge.props.forEach((prop) => { - - // Check if props exists in challengeRelations, if so add 1 - if (challengeRelations[prop]) { - challengeRelations[prop]++; - } - else { // if not create it - challengeRelations[prop] = 1; - }; - relationCount++; - }); + + // Check if challenge is incomplete before adding relation + if (!challenge.isComplete) { + + // Loop through challenge props + challenge.props.forEach((prop) => { + + // Check if props exists in challengeRelations, if so add 1 + if (challengeRelations[prop]) { + challengeRelations[prop]++; + } + else { // if not create it + challengeRelations[prop] = 1; + }; + relationCount++; + }); + }; }; - // Remove keys' values that are not more than 1 + // Remove values that are 1 or less bountyRelations = Object.fromEntries(Object.entries(bountyRelations).filter(([key, value]) => value > 1)); challengeRelations = Object.fromEntries(Object.entries(challengeRelations).filter(([key, value]) => value > 1)); // Add relation count to table subheading document.getElementById('relationsTotalField').innerHTML = relationCount; - // Merge relations - allRelations = {...bountyRelations, ...challengeRelations}; - + // Loop through bounty relations + for (let key in bountyRelations) { + + // Find value from pair + let value = bountyRelations[key]; - // Convert allRelations to percentages - allRelations = Object.entries(allRelations).map(([key, value]) => { - return [key, Math.trunc((value / relationCount) * 1000)]; - }); + // Store pair -- check if exists to create new key:value + if(allRelations[key]) { + allRelations[key] += value; + } + else { + allRelations[key] = value; + }; + }; + + // Loop through challenge relations + for (let key in challengeRelations) { + + // Find value from pair + let value = challengeRelations[key]; + + // Store pair -- check if exists to create new key:value + if(allRelations[key]) { + allRelations[key] += value; + } + else { + allRelations[key] = value; + }; + }; + + // Sort allRelations by relation count, in descending order + // Turn each object intro key:value with arrays + allRelations = Object.entries(allRelations).sort((a, b) => b[1] - a[1]); + bountyRelations = Object.entries(bountyRelations).sort((a, b) => b[1] - a[1]); + challengeRelations = Object.entries(challengeRelations).sort((a, b) => b[1] - a[1]); - // Sort allRelations by percentage - allRelations.sort((a, b) => b[1] - a[1]); + // Find average relation count + let averageRelationCount = relationCount / allRelations.length; + if (!relationCount || !isFinite(averageRelationCount)) { + averageRelationCount = 0; + }; - // Return all relations in the form of an object - return {bounties: bountyRelations, challenges: challengeRelations, all: allRelations}; + // Return each relations object + return { + bounties: bountyRelations, + challenges: challengeRelations, + all: allRelations, + averageRelationCount: averageRelationCount + }; }; \ No newline at end of file diff --git a/src/scripts/modules/ParseRace.js b/src/scripts/modules/ParseRace.js new file mode 100644 index 0000000..37d1069 --- /dev/null +++ b/src/scripts/modules/ParseRace.js @@ -0,0 +1,27 @@ + +// Parse the raceType number (1,2,3) into a string +// @number {raceType}, @boolean {isReverse} +export function ParseRace(raceType, isReverse = false) { + + // If isRerverse then we are turning the string version of the raceType, back into its number form + if (isReverse) { + switch (raceType) { + case 'Awoken': + return 1; + case 'Exo': + return 2; + case 'Human': + return 3; + }; + }; + + // Return corresponding string + switch (raceType) { + case 1: + return 'Awoken'; + case 2: + return 'Exo'; + case 3: + return 'Human'; + }; +}; diff --git a/src/scripts/modules/ParseSeasonalChallenges.js b/src/scripts/modules/ParseSeasonalChallenges.js index d79c9a3..9bd4e4a 100644 --- a/src/scripts/modules/ParseSeasonalChallenges.js +++ b/src/scripts/modules/ParseSeasonalChallenges.js @@ -1,11 +1,20 @@ import { stringMatchProgressionItem } from './StringMatchProgressionItem.js'; import { ReplaceStringVariables } from './ReplaceStringVariables.js'; +import { + seasonDefinitions, + recordDefinitions, + presentationNodeDefinitions, + progressionDefinitions, + UserProfile +} from '../user.js'; -// Return recordDefinition of current the seasons' challenges -// weekNumber: 1-xx where 0 is the "Complete all seasonal challenges" record -// Modular function, if weekNumber is passed, then it will only return challenges in that week, otherwise it will return all challenges -// @int {seasonHash}, @object {recordDefinitions}, @object {DestinyPresentationNodeDefinition}, @int {weekNumber} -export async function ParseSeasonalChallenges(seasonHash, seasonDefinitions, recordDefinitions, presentationNodeDefinitions, weekNumber) { +/* + Return recordDefinition of current the seasons' challenges + weekNumber: 1-xx where 0 is the "Complete all seasonal challenges" record + Modular function, if weekNumber is passed, then it will only return challenges in that week, otherwise it will return all challenges +*/ +// @int {seasonHash}, @object {seasonDefinitions}, @object {recordDefinitions}, @object {presentationNodeDefinitions}, @object {DestinyPresentationNodeDefinition} +export async function ParseSeasonalChallenges(seasonHash, seasonProgressionInfo) { // Self function to add props onto a challenge function addPropsToChallengeItem(seasonalChallenges) { @@ -18,37 +27,31 @@ export async function ParseSeasonalChallenges(seasonHash, seasonDefinitions, rec }; // Get the presentation node hash for the weekly challenges node - let seasonalChallengesNodeHash = presentationNodeDefinitions[seasonDefinitions[seasonHash].seasonalChallengesPresentationNodeHash].children.presentationNodes[0].presentationNodeHash, - seasonalChallenges = {}; + let seasonalChallengesNodeHash = presentationNodeDefinitions[seasonDefinitions[seasonHash].seasonalChallengesPresentationNodeHash].children.presentationNodes[0].presentationNodeHash; + let seasonalChallenges = {}; - // Check if weekNumber is passed - if (weekNumber) { + // Get all the child presentation node hashes for the weekly challenges (upto current week) + let seasonPresentationNodes = presentationNodeDefinitions[seasonalChallengesNodeHash].children.presentationNodes; + let availableSeasonalChallenges = []; + + // Store the amount of available seasonal challenges in UserProfile (global) + UserProfile.AssignMisc('challengesCount', availableSeasonalChallenges.length); - // Get the presentation node hash for the specified weekly challenges node - // Then get all the child record hashes for the challenges in that node - let specifiedSeasonWeekNodeHash = presentationNodeDefinitions[seasonalChallengesNodeHash].children.presentationNodes[weekNumber].presentationNodeHash; - let specifiedSeasonalChallengesInThatWeek = presentationNodeDefinitions[specifiedSeasonWeekNodeHash].children.records; - - // Loop through each challenge in that week and add it to the seasonalChallenges object - for (let record in specifiedSeasonalChallengesInThatWeek) { - let recordHash = specifiedSeasonalChallengesInThatWeek[record].recordHash; - let recordDescription = recordDefinitions[recordHash].displayProperties.description; + let startDate = new Date(seasonProgressionInfo.startDate).getTime(); + let todayDate = new Date().getTime(); + let weeksPassed = Math.trunc(todayDate - startDate) / (24*3600*1000*7); - // Check if progressionDescriptor has string variables to replace - if (recordDescription.includes('{')) { - recordDefinitions[recordHash].displayProperties.description = ReplaceStringVariables(recordDescription); - }; - seasonalChallenges[recordHash] = recordDefinitions[recordHash]; - }; + // Find the current (within the current week) seasonal challenges + for (let i=0; i { + this.progressions[type][item.hash] = item; + + // Increment misc counter for item type + this.misc[`${type}Count`]++; + }); + }, + AssignMisc: function(key, val) { + this.misc[key] = val; } }; export const UserProfileProgressions = { @@ -198,7 +213,7 @@ export var accentColor = { // Relations table metadata export var relationsTable = { div: {}, // DOM element - relations: { + relations: { // Specific to current character bounties: {}, challenges: {}, all: {} @@ -207,81 +222,166 @@ export var relationsTable = { pvp: true, pve: true, challenges: true, - bounties: true + expiredBounties: true }, ClearTable: function() { + + // Clear relations table this.div.innerHTML = ''; - this.div.innerHTML = 'ItemCategoryRelation'; + this.div.innerHTML = 'KeywordRelation'; + + let ctgs = ['ActivityMode', 'ItemCategory', 'DamageType', 'KillType', 'EnemyType']; + + // Clear relation squares + for (let item of ctgs) { + document.getElementById(`${item}Title`).className = 'relationSquareNormal'; + document.getElementById(`${item}Arrow`).src = './static/ico/neutral_ring.svg'; + document.getElementById(`${item}Arrow`).classList.remove('greenIco'); + document.getElementById(`${item}Text`).innerHTML = '--'; + }; }, BuildTable: function() { + function findAverage(typeString, item) { + if (item[1] > averageRelationCount) { + document.getElementById(`${typeString}Title`).className = 'relationSquareGreen'; + document.getElementById(`${typeString}Arrow`).src = './static/ico/blackArrow.svg'; + document.getElementById(`${typeString}Arrow`).classList.add('greenIco'); + } + else if (item[1] < averageRelationCount) { + document.getElementById(`${typeString}Title`).className = 'relationSquareOrange'; + document.getElementById(`${typeString}Arrow`).src = './static/ico/orangeArrow.svg'; + document.getElementById(`${typeString}Arrow`).classList.remove('greenIco'); + }; + + // Change the average up/down green/orange arrow based on the average relation count + document.getElementById(`${typeString}Text`).innerHTML = item[0]; + }; + /* - Collate all tables and standardize their format (so they are the same) - Filter out keys based on the toggles and pvp/pve filters - Sort the resulting table, in descending order, via the points (pts) of each key + Take relations and push each one as a row to the relations table + Filter relations based on which toggles are set to true or false */ - - // Clear tableF - // this.ClearTable(); - // Update relation count - // document.getElementById('relationsTotalField').innerHTML = Object.keys(this.relations[type]).length; - }, - BuildTableDeprecated: function(type) { - - // Clear table + // Clear table first and init this.ClearTable(); + let totalRelationCount = 0; + let totalItemCount = 0; + let averageRelationCount = this.relations.averageRelationCount; + + // Iterate over all relations + Object.keys(this.relations.all).forEach((relation) => { + + + // Check if challenges are toggled + if (!this.toggles.challenges) { + + // Loop over challenges and subtract each challenges' key value from relations.all + Object.keys(this.relations.challenges).forEach((challengeRelation) => { + if (this.relations.challenges[challengeRelation][0] === this.relations.all[relation][0]) { + this.relations.all[relation][1] -= this.relations.challenges[challengeRelation][1]; + }; + }); + }; - // Check if table will be empty - if (Object.keys(this.relations[type]).length === 0) { - AddTableRow(this.div, ['No relations found', '', '']); + // Check if properties have a value of zero -> omit + if (this.relations.all[relation][1] === 0) { + delete this.relations.all[relation]; + }; + }); + + // Rebuild relations.all objects + this.relations.all = Object.entries(this.relations.all).map(([key, value]) => value); + + // Sort relations.all via relationCount and descending order, before pushing rows to table + this.relations.all = Object.values(this.relations.all).sort((a,b) => b[1] - a[1]); + + + // Check table relation count(s) + if (Object.keys(this.relations.all).length === 0) { + document.getElementById('noRelationsExistElement').style.display = 'block'; + document.getElementById('tblCon').style.display = 'none'; + document.getElementById('relationsTotalField').innerHTML = '0'; return; + } + else { + document.getElementById('noRelationsExistElement').style.display = 'none'; + document.getElementById('tblCon').style.display = 'block'; }; - // Update table, looping over type - for (let relation in this.relations[type]) { + // Iterate over all relations again (after keys are removed otherwise emits undefined) + Object.keys(this.relations.all).forEach((a) => { - let itemName = relation; - let itemRelation = this.relations[type][relation]; - let itemCategory; + let itemName = this.relations.all[a][0]; + let itemRelationCount = this.relations.all[a][1]; - for (let item in progressionPropertyKeyValues) { + // Add property value to relation count + totalRelationCount += this.relations.all[a][1]; - // If relation is in category, store in category - log(itemName); - if (progressionPropertyKeyValues[item].includes(ParsePropertyNameIntoWord(itemName, true))) { - itemCategory = item; - }; + // Increment item count + totalItemCount++; + + // Add table row with item data + AddTableRow(this.div, [itemName, `${itemRelationCount}pts`]); + }); + + // To avoid oddly shaped table cells, check to see how much space is left in container + // and fill whitespace with empty cells + if (totalItemCount < 10) { + let requiredRows = 20 - totalItemCount; // 10 is the max rows before overflow occurs + for (let i=0; i value.includes(itemName)), itemName); - // // Check pvp toggle - // if (!this.toggles.pvp) { - // if (progressionPropertiesPVP.includes(itemCategory)) { - // continue; - // } - // else { - // return; - // }; - // }; - - // // Check pve toggle - // if (!this.toggles.pve) { - // if (progressionPropertiesPVE.includes(itemCategory)) { - // continue; - // } - // else { - // return; - // }; - // }; - - AddTableRow(this.div, [itemName, ParsePropertyNameIntoWord(itemCategory), `${itemRelation}pts`]); }; - // Update relation count - document.getElementById('relationsTotalField').innerHTML = Object.keys(this.relations[type]).length; + // Update table subheading relation count + document.getElementById('relationsTotalField').innerHTML = `${totalRelationCount}`; + + let highestActivityMode; + let highestItemCategory; // e.g. scout rifle + let highestDamageType; + let highestKillType; + let highestEnemyType; + + // Find the highest relation from each category + // allRelations is sorted so it should find the first match + this.relations.all.forEach(item => { + + let name = ParsePropertyNameIntoWord(item[0], true); + + if (ActivityMode.includes(name)) { + if (!highestActivityMode) { + highestActivityMode = name; + findAverage('ActivityMode', item); + }; + } + else if (ItemCategory.includes(name)) { + if (!highestItemCategory) { + highestItemCategory = name; + findAverage('ItemCategory', item); + }; + } + else if (DamageType.includes(name)) { + if (!highestDamageType) { + highestDamageType = name; + findAverage('DamageType', item); + }; + } + else if (KillType.includes(name)) { + if (!highestKillType) { + highestKillType = name; + findAverage('KillType', item); + }; + } + else if (EnemyType.includes(name)) { + if (!highestEnemyType) { + highestEnemyType = name; + findAverage('EnemyType', item); + }; + }; + }); } }; diff --git a/src/static/ico/blackArrow.svg b/src/static/ico/blackArrow.svg new file mode 100644 index 0000000..8b7eee8 --- /dev/null +++ b/src/static/ico/blackArrow.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/static/ico/arc_icon.png b/src/static/ico/destiny-icons/arc_icon.png similarity index 100% rename from src/static/ico/arc_icon.png rename to src/static/ico/destiny-icons/arc_icon.png diff --git a/src/static/ico/class_hunter.svg b/src/static/ico/destiny-icons/class_hunter.svg similarity index 100% rename from src/static/ico/class_hunter.svg rename to src/static/ico/destiny-icons/class_hunter.svg diff --git a/src/static/ico/class_titan.svg b/src/static/ico/destiny-icons/class_titan.svg similarity index 100% rename from src/static/ico/class_titan.svg rename to src/static/ico/destiny-icons/class_titan.svg diff --git a/src/static/ico/class_warlock.svg b/src/static/ico/destiny-icons/class_warlock.svg similarity index 100% rename from src/static/ico/class_warlock.svg rename to src/static/ico/destiny-icons/class_warlock.svg diff --git a/src/static/ico/heavy_ammo_icon.svg b/src/static/ico/destiny-icons/heavy_ammo_icon.svg similarity index 100% rename from src/static/ico/heavy_ammo_icon.svg rename to src/static/ico/destiny-icons/heavy_ammo_icon.svg diff --git a/src/static/ico/meditations.svg b/src/static/ico/destiny-icons/meditations.svg similarity index 100% rename from src/static/ico/meditations.svg rename to src/static/ico/destiny-icons/meditations.svg diff --git a/src/static/ico/power.svg b/src/static/ico/destiny-icons/power.svg similarity index 100% rename from src/static/ico/power.svg rename to src/static/ico/destiny-icons/power.svg diff --git a/src/static/ico/power2.svg b/src/static/ico/destiny-icons/power2.svg similarity index 100% rename from src/static/ico/power2.svg rename to src/static/ico/destiny-icons/power2.svg diff --git a/src/static/ico/primary_ammo_icon.svg b/src/static/ico/destiny-icons/primary_ammo_icon.svg similarity index 100% rename from src/static/ico/primary_ammo_icon.svg rename to src/static/ico/destiny-icons/primary_ammo_icon.svg diff --git a/src/static/ico/pursuit_completed.svg b/src/static/ico/destiny-icons/pursuit_completed.svg similarity index 100% rename from src/static/ico/pursuit_completed.svg rename to src/static/ico/destiny-icons/pursuit_completed.svg diff --git a/src/static/ico/pursuit_expired.svg b/src/static/ico/destiny-icons/pursuit_expired.svg similarity index 100% rename from src/static/ico/pursuit_expired.svg rename to src/static/ico/destiny-icons/pursuit_expired.svg diff --git a/src/static/ico/pursuits.svg b/src/static/ico/destiny-icons/pursuits.svg similarity index 100% rename from src/static/ico/pursuits.svg rename to src/static/ico/destiny-icons/pursuits.svg diff --git a/src/static/ico/solar_icon.png b/src/static/ico/destiny-icons/solar_icon.png similarity index 100% rename from src/static/ico/solar_icon.png rename to src/static/ico/destiny-icons/solar_icon.png diff --git a/src/static/ico/special_ammo_icon.svg b/src/static/ico/destiny-icons/special_ammo_icon.svg similarity index 100% rename from src/static/ico/special_ammo_icon.svg rename to src/static/ico/destiny-icons/special_ammo_icon.svg diff --git a/src/static/ico/stasis_icon.png b/src/static/ico/destiny-icons/stasis_icon.png similarity index 100% rename from src/static/ico/stasis_icon.png rename to src/static/ico/destiny-icons/stasis_icon.png diff --git a/src/static/ico/tab_icon.png b/src/static/ico/destiny-icons/tab_icon.png similarity index 100% rename from src/static/ico/tab_icon.png rename to src/static/ico/destiny-icons/tab_icon.png diff --git a/src/static/ico/vault.svg b/src/static/ico/destiny-icons/vault.svg similarity index 100% rename from src/static/ico/vault.svg rename to src/static/ico/destiny-icons/vault.svg diff --git a/src/static/ico/void_icon.png b/src/static/ico/destiny-icons/void_icon.png similarity index 100% rename from src/static/ico/void_icon.png rename to src/static/ico/destiny-icons/void_icon.png diff --git a/src/static/ico/xp_icon.ico b/src/static/ico/destiny-icons/xp_icon.ico similarity index 100% rename from src/static/ico/xp_icon.ico rename to src/static/ico/destiny-icons/xp_icon.ico diff --git a/src/static/ico/xp_icon.svg b/src/static/ico/destiny-icons/xp_icon.svg similarity index 100% rename from src/static/ico/xp_icon.svg rename to src/static/ico/destiny-icons/xp_icon.svg diff --git a/src/static/ico/icon.png b/src/static/ico/icon.png new file mode 100644 index 0000000..40a392c Binary files /dev/null and b/src/static/ico/icon.png differ diff --git a/src/static/ico/icon.svg b/src/static/ico/icon.svg new file mode 100644 index 0000000..c7d4682 --- /dev/null +++ b/src/static/ico/icon.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/static/ico/neutral_ring.svg b/src/static/ico/neutral_ring.svg new file mode 100644 index 0000000..1f094f6 --- /dev/null +++ b/src/static/ico/neutral_ring.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/static/ico/orangeArrow.svg b/src/static/ico/orangeArrow.svg new file mode 100644 index 0000000..8047649 --- /dev/null +++ b/src/static/ico/orangeArrow.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/static/ico/tooltip_icon.svg b/src/static/ico/tooltip_icon.svg new file mode 100644 index 0000000..4f070b5 --- /dev/null +++ b/src/static/ico/tooltip_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/static/images/1e2245842aa33a77fcbaeaa874e35f2a.png b/src/static/images/1e2245842aa33a77fcbaeaa874e35f2a.png deleted file mode 100644 index a2ff6b9..0000000 Binary files a/src/static/images/1e2245842aa33a77fcbaeaa874e35f2a.png and /dev/null differ diff --git a/src/static/images/9fb5b76d329c851ea48c2a82abba7b44.png b/src/static/images/9fb5b76d329c851ea48c2a82abba7b44.png deleted file mode 100644 index b559bf9..0000000 Binary files a/src/static/images/9fb5b76d329c851ea48c2a82abba7b44.png and /dev/null differ diff --git a/src/static/images/UI/metric_backplate_L.png b/src/static/images/UI/metric_backplate_L.png new file mode 100644 index 0000000..9933efc Binary files /dev/null and b/src/static/images/UI/metric_backplate_L.png differ diff --git a/src/static/images/UI/metric_backplate_m.png b/src/static/images/UI/metric_backplate_m.png new file mode 100644 index 0000000..f35e947 Binary files /dev/null and b/src/static/images/UI/metric_backplate_m.png differ diff --git a/src/static/images/UI/metric_backplate_s.png b/src/static/images/UI/metric_backplate_s.png new file mode 100644 index 0000000..4eff984 Binary files /dev/null and b/src/static/images/UI/metric_backplate_s.png differ diff --git a/src/static/images/UI/metric_backplate_sm.png b/src/static/images/UI/metric_backplate_sm.png new file mode 100644 index 0000000..696ef48 Binary files /dev/null and b/src/static/images/UI/metric_backplate_sm.png differ diff --git a/src/static/images/UI/season_rank_backplate.svg b/src/static/images/UI/season_rank_backplate.svg new file mode 100644 index 0000000..e69075b --- /dev/null +++ b/src/static/images/UI/season_rank_backplate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/static/images/UI/season_rank_prestige_backplate.svg b/src/static/images/UI/season_rank_prestige_backplate.svg new file mode 100644 index 0000000..15c1361 --- /dev/null +++ b/src/static/images/UI/season_rank_prestige_backplate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/static/images/UI/statistic_container_bg.svg b/src/static/images/UI/statistic_container_bg.svg new file mode 100644 index 0000000..e221c7c --- /dev/null +++ b/src/static/images/UI/statistic_container_bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/static/images/artifact_background.jpg b/src/static/images/artifact_background.jpg deleted file mode 100644 index 4f8b8ec..0000000 Binary files a/src/static/images/artifact_background.jpg and /dev/null differ diff --git a/src/static/images/emblem2.jpg b/src/static/images/emblem2.jpg deleted file mode 100644 index b530db3..0000000 Binary files a/src/static/images/emblem2.jpg and /dev/null differ diff --git a/src/static/images/emblem3.jpg b/src/static/images/emblem3.jpg deleted file mode 100644 index 9fc85d4..0000000 Binary files a/src/static/images/emblem3.jpg and /dev/null differ diff --git a/src/static/images/engram_outline.png b/src/static/images/engram_outline.png deleted file mode 100644 index 4060b0e..0000000 Binary files a/src/static/images/engram_outline.png and /dev/null differ diff --git a/src/static/images/eververse.png b/src/static/images/eververse.png deleted file mode 100644 index f54c9ae..0000000 Binary files a/src/static/images/eververse.png and /dev/null differ diff --git a/src/static/images/seasonal_background.jpg b/src/static/images/seasonal_background.jpg deleted file mode 100644 index e6b4742..0000000 Binary files a/src/static/images/seasonal_background.jpg and /dev/null differ diff --git a/src/styles/item.css b/src/styles/item.css index 6c3728e..d6e30d6 100644 --- a/src/styles/item.css +++ b/src/styles/item.css @@ -4,16 +4,26 @@ * Every reference of an item in the DOM, will use this style script to apply style */ +:root { + --completedCheckboxOuter: rgba(255, 255, 255, 0.6); + --completedCheckboxMiddle: rgba(0, 0, 0, 0.5); + --completedCheckboxInner: #5AA366; + --challengeCompletedCheckboxOuter: rgba(255, 255, 255, 0.371); + --challengeCompletedCheckboxMiddle: rgba(0, 0, 0, 0.304); + --challengeCompletedCheckboxInner: #14798b; +} + .overlayContainer { display: none; position: relative; width: 210px; min-height: 260px; + margin-left: -230px; background-color: rgba(0, 0, 0, 0.639); backdrop-filter: blur(6px); border: 1px solid rgba(87, 87, 87, 0.66); z-index: 99; - box-shadow: 2px 2px 2px #3F3F3F; + box-shadow: 0 25px 40px #000000e6; pointer-events: none; } @@ -42,6 +52,40 @@ z-index: -10; } +.itemHeader { + padding-bottom: 10px; + background-color: #B2ACA6; +} + +.itemAttributes { + padding-top: 10px; +} + +.objectiveContainer { + display: flex; + flex-direction: row; + gap: 10px; +} + +.objectiveCheckboxOuter { + border: 1.5px solid rgba(255, 255, 255, 0.8); + width: 13px; + height: 13px; +} + +.objectiveCheckboxMiddle { + border: 1.5px solid rgba(0, 0, 0, 0.2); + width: 11px; + height: 11px; +} + +.objectiveCheckboxInner { + border: none; + width: 11px; + height: 11px; + background-color: none; +} + #itemDesc { padding-left: 10px; padding-right: 1em; @@ -93,7 +137,7 @@ } #bountyItems { - margin-top: 30px; + margin-top: 10px; } #bountyItems > div { @@ -111,6 +155,7 @@ border: 1px solid rgba(200, 200, 200, 0.749); border-radius: 1px; z-index: 1; + cursor: help; } .statusIcon { @@ -134,57 +179,18 @@ #itemTitle { padding-top: 13px; padding-left: 10px; - color: white; + color: rgb(23, 23, 23); font-family: "Neue Haas Grotesk Display", "Destiny Symbols", Segoe-MDL, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; font-weight: bold; } #itemType { padding-left: 12px; - color: white; + color: rgb(62, 62, 62); font-family: "Neue Haas Grotesk Display", "Destiny Symbols", Segoe-MDL, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; - font-style: italic; font-size: 11px; } .greyOut { opacity: 50%; } - -.filter { - display: inline-block; - width: fit-content; - cursor: pointer; - background-color: rgba(0, 0, 0, 0.639); - border: 1px solid #292929; - border-radius: 15px; -} - -#btnHideFilters { - display: none !important; - margin-top: 10px; - margin-left: 2px; - padding: 3px; - width: fit-content; - color: #CDCBCB; - border: 1px #CDCBCB solid; - border-radius: 4px; - cursor: pointer; - font-family: "Neue Haas Grotesk Display", "Destiny Symbols", Segoe-MDL, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; - font-size: 10px; - transition: 0.25s; -} -#btnHideFilters:hover { - color: white; - border-color: white; - transition: 0.25s; -} - -.propName { - padding: 6px; - padding-top: 3px; - padding-bottom: 3px; - color: #8A8A8A; - font-family: "Neue Haas Grotesk Display", "Destiny Symbols", Segoe-MDL, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; - font-size: 12px; -} \ No newline at end of file diff --git a/src/styles/src.css b/src/styles/src.css index 3f54d57..67c4920 100644 --- a/src/styles/src.css +++ b/src/styles/src.css @@ -29,7 +29,7 @@ body { user-select: none; - font-family: "Neue Haas Grotesk Display", "Destiny Symbols", Segoe-MDL, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", NotoColorEmoji, "Segoe UI Symbol", "Android Emoji", EmojiSymbols; + font-family: var(--DestinyUIFont); background-color: #22272e; } @@ -62,7 +62,7 @@ h2 { width: 100vw; background-color: rgba(237, 77, 77, 0.8); box-shadow: 0px 0px 10px 1px #ED4D4D; - z-index: 99; /* Keep box shadow on top of navbar */ + z-index: 201; /* Keep box shadow on top of navbar */ } #navBarContainer { @@ -76,7 +76,7 @@ h2 { justify-content: space-between; align-items: center; text-align: center; - z-index: 10; + z-index: 200; } #navBarTitleContainer { @@ -205,7 +205,6 @@ h2 { #warnIcon { margin-top: -1px; width: 20px; - cursor: pointer; } /* Logout button for mobile */ @@ -228,15 +227,17 @@ h2 { } .warningTooltip { + position: absolute; display: flex; padding: 8px; - margin-top: 10px; - bottom: 10px; + padding-top: 10px; + margin-bottom: 15px; + bottom: 0; width: 90%; gap: 5px; border: 1px rgb(255, 175, 15) solid; border-radius: 5px; - background-color: rgba(255, 143, 15, 0.6); + background-color: rgba(255, 158, 54, 0.634); } .warningTooltipLink { @@ -246,7 +247,7 @@ h2 { /* Notification */ #notificationContainer { - position: absolute; + position: fixed; display: none; bottom: 0; right: 0; @@ -257,6 +258,7 @@ h2 { opacity: 1; background-color: #202020; color: white; + z-index: 199; } #notificationContainer.fade-out { @@ -551,43 +553,6 @@ h2 { } -/* Loadbar */ -#loadBarContainer { - display: none; - position: absolute; - top: 0px; -} -#slider{ - position: absolute; - margin-left: -10px; - width: 103vw; - height: 2px; - overflow-x: hidden; -} -.subline{ - position: absolute; - height: 2px; - background: #22272E; - overflow-x: hidden; - border-radius: 3px; - z-index: 100; -} -.inc{ - animation: increase 2s infinite; -} -.dec{ - animation: decrease 2s 0.5s infinite; -} -@keyframes increase { - from { left: -5%; width: 5%; } - to { left: 130%; width: 100%; } -} -@keyframes decrease { - from { left: -80%; width: 80%; } - to { left: 110%; width: 10%; } -} - - /* Onload Animation */ .fade-in { animation-name: FadeIn; @@ -663,17 +628,6 @@ hr { border-top: 1px solid gray; } -hr.horizontalRuler { - padding: 0; - margin: 0; - margin-top: 10px; - margin-bottom: 10px; - height: 1px; - width: 100%; - border: none; - background-color: #adadad; -} - @keyframes rotating { from { -ms-transform: rotate(0deg); diff --git a/src/styles/user.css b/src/styles/user.css index 4fc0fd5..b79e9dd 100644 --- a/src/styles/user.css +++ b/src/styles/user.css @@ -4,6 +4,12 @@ * Style for user.html, does not contain media queries */ +body { + height: 100vh; + overflow-y: hidden; + background: radial-gradient(rgb(45, 45, 45), #202020); +} + .contentHeading { font-size: var(--fontSizeHeading); } @@ -18,10 +24,6 @@ z-index: 0; } -#dropdownYield { - user-select: all; -} - #githubIcon { width: 23px; filter: invert(22%) sepia(0%) saturate(1%) hue-rotate(7deg) brightness(97%) contrast(83%); @@ -43,19 +45,6 @@ filter: invert(22%) sepia(0%) saturate(1%) hue-rotate(7deg) brightness(80%) contrast(83%); } -.propertySubheadings { - display: inline-block; - font-size: 15px; - font-weight: 600; - font-family: var(--SegoeUIFont); -} - -.propertyNames { - display: inline-block; - font-size: 15px; - font-family: var(--SegoeUIFont); -} - .propertySecretIcon { display: none; width: 40px; @@ -248,6 +237,11 @@ font-size: var(--fontSizeContent); } +#defaultViewDropdownContainer { + margin-top: 15px; + margin-left: 5px; +} + .labelRangeContainer { width: 90%; font-size: var(--fontSizeContent); @@ -316,35 +310,115 @@ padding: 15px; height: 90vh; width: 95vw; - border: solid 1px rgb(50, 50, 50); - background-color: #3e4148; + border: 1px #56606d solid; + background-color: #2e3238; border-radius: 8px; } -#relationsTableContainer { - margin-top: 15px; +#relationsTableContent { + position: relative; + display: flex; + gap: 10px; + margin-top: 10px; + max-height: 395px; +} + +#tblCon { + display: block; + width: 100%; + max-height: 100%; overflow-y: scroll; - max-height: 80%; } #relationsTable { + /* display: none; */ + width: 100%; + height: 100%; +} + +#noRelationsExistElement { + display: none; width: 100%; - user-select: text; - border: 1px solid rgba(52, 52, 52, 0.601); + background-color: rgba(255, 255, 255, 0.1); + filter: blur(50%); +} + +#noRelationsExistText { + display: block; + margin: 0 auto; + margin-top: 100px; + width: 80%; + text-align: center; + justify-content: center; +} + +#relationSquares { + display: flex; + flex-direction: column; + width: 30%; + gap: 10px; + user-select: none; +} + +#relationSquares > div { + padding: 8px; + background-color: rgb(33, 33, 33); + border-radius: 5px; + border: 1px solid rgb(101, 101, 101); + justify-content: center; + text-align: center; +} + +.relationSquareTitleContainers { + display: flex; + margin: 0 auto; + gap: 5px; + justify-content: center; + text-align: center; + justify-content: center; +} + +.relationSquareGreen .relationSquareOrange .relationSquareNormal { + font-size: 17px; + font-weight: 600; +} + +.relationSquareGreen { + color: green; +} +.relationSquareOrange { + color: orange; +} + +.relationSquareEmbed { + padding: 4px; + margin-top: 5px; + background-color: rgb(80, 80, 80); + border-radius: 4px; +} + +.relationSquareIco { + width: 13px; +} + +.greenIco { + filter: invert(50%) sepia(12%) saturate(2719%) hue-rotate(84deg) brightness(92%) contrast(86%); } td, th { - text-align: left; padding: 5px; padding-top: 7px; padding-bottom: 7px; + text-align: left; } th { + height: 20px; padding-bottom: 12px; } tr { + width: 100%; border-bottom: 1px solid rgba(128, 128, 128, 0.468); } @@ -384,45 +458,6 @@ tr:nth-child(even) { height: 0; } -.slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: #ccc; -} - -.slider:before { - position: absolute; - content: ""; - height: 13px; - width: 13px; - left: 4px; - bottom: 4px; - background-color: white; -} - -input:checked+.slider { - background-color: var(--accentColor); -} - -input:checked+.slider:before { - -webkit-transform: translateX(18px); - -ms-transform: translateX(18px); - transform: translateX(18px); -} - -/* Rounded sliders */ -.slider.round { - border-radius: 34px; -} - -.slider.round:before { - border-radius: 50%; -} - .settingsAccentColorButton { height: 20px; @@ -641,9 +676,89 @@ input:checked+.slider:before { /* ######### */ #defaultCharacterSelect { - padding-bottom: 30px; - width: fit-content; - filter: brightness(80%); + display: flex; + flex-direction: column; + gap: 4px; + padding-bottom: 25px; +} + +.characterSelect { + position: relative; + display: grid; + padding-left: 10px; + margin: 1px; + gap: 1rem; + grid-template-columns: 36px 1fr 75px; + width: 100%; + height: 50px; + color: white; + background-color: rgb(80, 80, 80, 0.6); + align-items: center; + cursor: pointer; +} + +.characterSelect > div { + z-index: 99; +} + +.characterSelect:hover { + border: 1px solid white; + margin: unset; +} + +.characterBg { + position: absolute; + padding: 0; + margin: 0; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(90deg,#89323800 50%,rgba(200, 200, 200, 0.5)); + overflow: hidden; + z-index: -1; +} + +.characterClassIco { + display: block; + margin-left: auto; + margin-right: 40px; + margin-top: -10px; + width: 40%; + opacity: 90%; + /* filter: invert(21%) sepia(47%) saturate(1408%) hue-rotate(317deg) brightness(100%) contrast(90%); */ +} + +.characterEmblemIco { + width: 38px; +} + +.characterInfo { + align-items: left; +} + +.characterClass { + font-size: 17px; +} + +.characterRace { + font-size: 13px; + color: #fff9; +} + +.characterPowerCon { + display: flex; +} + +.characterPower { + font-size: 24px; + color: #e5d163; +} + +.powerIcon { + margin-top: -5px; + width: 13px; + filter: invert(91%) sepia(18%) saturate(1236%) hue-rotate(356deg) brightness(94%) contrast(91%); } .characterSelectSlim { @@ -653,7 +768,6 @@ input:checked+.slider:before { text-align: center; height: 30px; width: 100%; - /* background-color: black; */ overflow-x: hidden; background-position: center; background-size: contain; @@ -661,6 +775,41 @@ input:checked+.slider:before { cursor: pointer; } +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; +} +.slider:before { + position: absolute; + content: ""; + height: 13px; + width: 13px; + left: 4px; + bottom: 4px; + background-color: white; +} +input:checked+.slider { + background-color: var(--accentColor); +} +input:checked+.slider:before { + -webkit-transform: translateX(18px); + -ms-transform: translateX(18px); + transform: translateX(18px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} +.slider.round:before { + border-radius: 50%; +} + .dropdownArrow { width: 12px; filter: invert(100%) brightness(50%); @@ -702,6 +851,10 @@ input:checked+.slider:before { color: gray; } +.hyperlinkBlue { + color: rgb(146, 171, 230); +} + .pre { max-height: 0px; } @@ -834,19 +987,15 @@ input:checked+.slider:before { letter-spacing: 1px; } -#sideSelectionBar { - display: none; - float: left; - margin-left: 5px; +.seasonalChallengesUIContainer { + display: flex; + margin-top: 15px; + gap: 10px; } #seasonalChallengesContainer, #statisticsContainer { display: none; -} - -#seasonChallengeControlGridContainer { - display: inline-flex; - width: 100%; + font-family: var(--DestinyUIFont); } .seasonalChallengePageButton { @@ -885,9 +1034,35 @@ input:checked+.slider:before { } .challengeContainer { - border: 1px solid #8C8C8C; - background-color: rgba(60, 60, 60, 0.461); font-family: var(--SegoeUIFont); + width: 100%; +} + +.challengeContainerNotComplete { + border: 2px solid #8C8C8C; + background-color: #3c3c3c76; + background: linear-gradient(transparent, transparent, transparent, rgba(10, 111, 132, 0.5)); +} + +.challengeContainerComplete { + border: 2px solid #3798a9; + background-color: #1c5863; +} + +.challengeContainerCompletedNotClaimed { + border: 2px solid #a4dbcc; + background-color: #314b47; +} + +.challengeHeadingContainer { + display: flex; + gap: 5px; +} + +.challengeHeadingAttributeContainer { + display: flex; + margin-top: 10px; + flex-direction: column; } .bountyIcon { @@ -900,27 +1075,12 @@ input:checked+.slider:before { } .challengeName { - margin-top: -45px; - margin-left: 55px; - text-transform: uppercase; - font-weight: 600; - font-size: 18px; width: 275px; - letter-spacing: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; -} - -hr.challengeBreakline { - padding: none; - margin: auto; - margin-top: 15px; - width: 95%; - height: 1px; - border: none; - border-radius: 1px; - background-color: #7e8891; + font-weight: 600; + font-family: var(--DestinyUIFont); } hr.dropdownLine { @@ -948,13 +1108,176 @@ hr.dropdownSubline { padding-bottom: 5px; gap: 8px; cursor: pointer; + user-select: none; } -.challengeDescription { +.sharedWisdomWarningIcon { + display: none; + position: absolute; + padding: 7px; + margin-left: 80px; + margin-top: -50px; + border: 1px solid rgb(120, 120, 120); + border-radius: 3px; + width: fit-content; + color: white; + background-color: rgb(50, 50, 50); + font-size: 13px; + z-index: 99; +} + +.userHelpHoverIcon { margin-top: 3px; - margin-left: 8px; - margin-bottom: 10px; - width: 90%; + width: 14px; + height: 14px; + filter: invert(78%) sepia(95%) saturate(2%) hue-rotate(312deg) brightness(113%) contrast(103%); +} + +.tooltipContainer { + position: absolute; + display: none; + padding: 8px; + margin-top: 10px; + margin-left: 200px; + border: 1px solid gray; + border-radius: 5px; + background-color: rgb(50,50,50); + font-size: 13px; + z-index: 99; +} + +.userToggleContainer { + display: flex; + margin-top: 8px; + gap: 5px; + align-items: center; + color: white; +} + +#recommendationTooltip { + display: none; + margin-top: 5px; + font-style: italic; + color: rgba(17, 17, 17, 0.83); +} + +.statsColumnContainer { + display: flex; + max-height: 100%; + overflow-y: scroll; + gap: 11px; + flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +.statContainer { + padding-left: 14px; + padding-top: 7px; + height: 200px; + border: 1px solid #1E1E1E; + background-color: #323134; + background-image: url("../static/images/UI/statistic_container_bg.svg"); + background-size: 60%; + background-repeat: repeat; + background-position-y: -2px; +} + +.statHeadingContainer { + display: flex; + flex-direction: column; + gap: -5px; +} + +.statContainerSubheading { + font-size: 13px; + color: #A5A5A5; +} + +.statContainerMainHeading { + font-size: 20px; + font-weight: 600; + color: white; + letter-spacing: 0.3px; +} + +.statMetricsContainer { + display: flex; + margin-top: 9px; + padding: 8px; + padding-left: 9px; + padding-right: 9px; + width: fit-content; + height: 130px; + gap: 10px; + background-color: rgba(0, 0, 0, 0.6); +} + +.statMetricsContainer > div { + padding-top: 4px; + padding-left: 8px; + padding-right: 8px; + width: 100px; + border: solid 1px #555555; +} + +.metricSubheading { + font-size: 14px; + line-height: 1.4; + color: #fff9; +} + +.metricHeading { + margin-top: -3px; + font-size: 16px; + color: white; +} + +.seasonRankMetricContainer { + margin-top: 5px; + margin-left: 0px; + margin-right: 0px; + text-align: center; +} + +#seasonRankMetric { + margin-top: -59px; + margin-left: -2px; + font-size: 24px; + font-weight: bold; +} + +#toggleMetricTooltipsButton { + display: flex; + margin-top: 6px; + margin-left: 1px; + padding-top: 4px; + padding-left: 5px; + padding-right: 7px; + width: fit-content; + height: 16px; + gap: 5px; + background-color: black; + opacity: 60%; + border-radius: 3px; + border: solid 1px transparent; + font-size: 12px; + color: white; + cursor: pointer; +} + +#toggleMetricTooltipsButton:hover { + border: solid 1px white; +} + +.toggleMetricTooltipIcon { + margin-top: -3px; + width: 11px; +} + +.challengeDescription { + width: 95%; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; @@ -963,6 +1286,29 @@ hr.dropdownSubline { -webkit-box-orient: vertical; } +.challengeRewardsContainer { + display: flex; + margin-top: 5px; + margin-bottom: 5px; + gap: -20px; + flex-direction: column; +} + +.challengeRewardName { + font-size: 14px; +} + +.singleChallengeRewardContainer { + display: flex; + margin-left: 10px; +} + +.challengeRewardIcon { + margin-right: 3px; + width: 18px; + height: 18px; +} + .challengeProgressContainer { width: 100%; height: 8px; @@ -983,49 +1329,37 @@ hr.dropdownSubline { z-index: 10; } -#levellingStatisticsContainer { - display: none; -} - -.containerTitle { - margin-top: -7px; - margin-bottom: -12px; - text-transform: uppercase; - font-size: 23px; - font-weight: 600; - font-family: var(--SegoeUIFont); - letter-spacing: 1px; +.challengeProgressAttributesContainer { + display: flex; + margin-left: 11px; + margin-right: 10px; + flex-direction: column; + gap: 3px; } -.subheadingFields { - display: inline-block; - padding-right: 3px; - font-size: 15px; - font-family: var(--SegoeUIFont); +.objectiveAttributes { + display: flex; + padding-left: 10px; + padding-right: 10px; + width: 100%; + height: 14px; + background-color: rgba(38, 38, 38, 0.322); + color: white; + font-size: 12px; } -#bountiesFieldSubText { - display: inline-block; - font-size: 15px; - font-family: var(--SegoeUIFont); +.objectiveName { + margin-top: -2px; + width: 100%; } -.levellingContainerTitle { - margin-top: 36px; - margin-bottom: 7px; - text-transform: uppercase; - color: white; - font-size: 23px; - font-weight: 600; - font-family: var(--SegoeUIFont); - letter-spacing: 1px; +.objectiveProgress { + margin-top: -2px; } -#currentSeasonNameField { - display: inline-block; - color: white; - font-size: 15px; - font-family: var(--SegoeUIFont); +.objectiveContainer { + display: flex; + gap: 5px; } #noBountiesTooltip { @@ -1036,31 +1370,6 @@ hr.dropdownSubline { font-style: italic; } -#categories { - display: none; - margin-top: 3px; -} - -#categories > div { - padding-top: 7px; - padding-bottom: 7px; - color: #CDCBCB; - letter-spacing: 1px; - cursor: pointer; - transition: 0.25s; -} - - -#cgSeasonalChalls:hover { - color: white; - transition: 0.25s; -} - -#cgBounties:hover { - color: white; - transition: 0.25s; -} - #questDisplayContainer { margin-top: 15px; } @@ -1099,29 +1408,6 @@ hr.dropdownSubline { animation: skeletonLoadAnimation 2s ease-in infinite; } -#charactersContainer { - display: none; -} - -#charactersContainer > div { - display: none; - cursor: pointer; -} - -.classBg { - width: 220px; -} - -.classType { - position: absolute; - margin-left: 43px; - margin-top: 5px; - color: white; - font-weight: 0; - letter-spacing: 1.3px; - font-size: 18px; -} - .classLight { position: absolute; margin-left: 54px; @@ -1131,237 +1417,17 @@ hr.dropdownSubline { font-size: 15px; } -.lightIcon { - position: absolute; - margin-left: 45px; - margin-top: 28px; - width: 8px; -} - -#statsContainer { - margin-top: 50px; - width: 75%; -} - #seasonalStatsContainer { display: none; margin-top: 50px; width: 75%; } -#statsTitle { - display: inline-block; - padding-bottom: 7px; - text-align: left; - color: #CDCBCB; - font-weight: bold; - letter-spacing: 1px; -} - -#baseStatsTitle { - display: inline-block; - margin-top: 16px; - text-align: left; - color: #CDCBCB; - font-weight: bold; - letter-spacing: 1px; -} - -#statsTitleQuery { - display: inline-block; - margin-left: 8px; - width: 14px; - filter: invert(48%) sepia(13%) saturate(3207%); -} - -#queryDiv { - position: absolute; - display: none; - padding: 3px; - left: 95px; - width: 90px; - color: #CDCBCB; - font-size: 11px; - background-color: #313131; - border: 1px solid #585858; - border-radius: 3px; -} - #loadingContentContainer { display: none !important; text-align: center; } -#filterContentContainer { - display: none; -} - -#baseStatsContainer { - margin-top: 10px; -} - -#baseStatsContainer > div { - display: inline-block; - padding-top: 3px; - padding-bottom: 3px; - color: #CDCBCB; -} - -#netStatsContainer { - margin-top: 10px; -} - -#netStatsContainer > div { - padding-top: 3px; - padding-bottom: 3px; - color: #CDCBCB; -} - -.statsCheckmark { - display: inline-block; - margin-right: 5px; - width: 13px; - filter: invert(82%) sepia(20%) saturate(1304%) hue-rotate(78deg) brightness(85%) contrast(90%); -} - -.statsCross { - display: none; - margin-right: 5px; - width: 13px; -} - -.netStatBuffHeading { - display: inline-block; - color: #8DDBFF !important; - font-style: italic; - text-decoration: underline; -} - -.popupArrow { - position: absolute; - display: inline-block; - margin-top: -17px; - width: 12px; - filter: invert(10%); - transform: rotate(90deg); -} - -.percentagePopup { - position: absolute; - display: inline-block; - margin-top: -25px; - margin-left: 8px; - padding: 5px; - width: 45px; - text-align: center; - font-variant-numeric: normal; - background-color: #1A1A1E; - border-radius: 3px; -} - -#sharedWisdomPopupContainer { - position: absolute; - display: none; - margin-top: 20px; - margin-left: 5px; -} - -#ghostModPopupContainer { - position: absolute; - display: none; - margin-top: 20px; - margin-left: 5px; -} - -#BonusXpPopupContainer { - position: absolute; - display: none; - margin-top: 20px; - margin-left: 5px; -} - -.netXpHeading { - display: inline-block; - margin-top: 10px; -} - -#totalNetXpField { - display: inline-block; -} - -.propertyStatisticContainer { - display: table; - padding: 5px; - padding-left: 10px; - padding-right: 10px; - margin: 0 auto; - background-color: #1B1B1B; - border: 1px solid #646464; - border-radius: 5px; - justify-content: left; - text-align: left; -} - -.propertyStatisticContainerForDestinations { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - padding: 5px; - padding-left: 10px; - padding-right: 10px; - margin: 0 auto; - background-color: #1B1B1B; - border: 1px solid #646464; - border-radius: 5px; - justify-content: left; - text-align: left; -} - -.propertyStatisticContainerForDestinations > div { - padding-bottom: 5px; -} - -.propertySubContainer { - display: inline-block; - padding: 5px; - margin: 0 auto; -} - -.propertySubContainer2 { - display: inline-block; - padding: 5px; - margin: 0 auto; - width: 120px; - text-align: center; - justify-content: center; -} - -#synergiesContainer { - display: flex; - margin-top: 15px; - height: 100%; -} - -#middleGroup { - margin-left: 15px; - height: 10%; -} - -#leftGroup { - height: 100%; -} - -#rightGroup { - margin-left: 15px; - width: fit-content; - height: 100%; -} - -.propertyTextName { - margin-bottom: 5px; - font-size: 16px; - -} - .weaponTypeContainer { display: inline-block; margin: auto; @@ -1370,92 +1436,6 @@ hr.dropdownSubline { justify-content: center; } -.weaponTypeIcon { - display: block; - margin-bottom: 5px; - width: 50px; - filter: invert(100%); -} - -.weaponTypePercentageField { - display: block; - margin: 0 auto; - padding-top: 2px; - padding-bottom: 2px; - padding-left: 4px; - padding-right: 4px; - width: fit-content; - background-color: #464646; - border: 1px solid #646464; - border-radius: 3px; - font-size: 15px; - font-variant-numeric: tabular-nums; -} - -.elementalSubContainer { - display: inline-block; - margin: auto; - margin-right: 5px; - text-align: center; - justify-content: center; -} - -.elementalIcon { - margin-bottom: 5px; - width: 40px; -} - -.elementalPercentageField { - display: block; - margin: 0 auto; - padding-top: 2px; - padding-bottom: 2px; - padding-left: 4px; - padding-right: 4px; - width: fit-content; - background-color: #464646; - border: 1px solid #646464; - border-radius: 3px; - font-size: 15px; - font-variant-numeric: tabular-nums; -} - -.ammoPercentageField { - display: block; - margin: 0 auto; - padding-top: 2px; - padding-bottom: 2px; - padding-left: 4px; - padding-right: 4px; - width: fit-content; - background-color: #464646; - border: 1px solid #646464; - border-radius: 3px; - font-size: 15px; - font-variant-numeric: tabular-nums; -} - -.ammoSubContainer { - display: inline-block; - margin: auto; - margin-right: 5px; - text-align: center; - justify-content: center; -} - -.ammoSubContainer > div { - position: relative; - left: 49%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.ammoIcon { - margin-bottom: 5px; - width: 40px; -} - #levellingContentDisplay > div { padding-top: 7px; padding-bottom: 3px; @@ -1468,108 +1448,6 @@ hr.dropdownSubline { color: #CDCBCB; } -#statsTableLayoutContainer { - display: inline-block; - margin-top: 8px; -} -#statsTableLayoutContainer > div { - width: 350px; - height: 150px; - padding: 2px; - border: #555 1px solid; - border-radius: 5px; - color: white; -} - -.containerMetricNumber { - display: inline-block; - color: #8DDBFF; -} - -/* Seasonal artifact statistic container */ -#artifactStats { - /* display: inline-block; */ - text-align: center; -} -#artifactStatsBg { - background-image: url('../static/images/artifact_background.jpg'); - background-size: cover; - width: 100%; - height: 100%; - z-index: -1; - filter: brightness(50%) blur(var(--blurFilterAmount)); -} -#artifactStatsContentContainer { - position: absolute; - text-align: left; - margin-top: -140px; - margin-left: 15px; -} -#artifactStatsFirstContainer { - margin-top: 13px; - font-size: 22px; -} -#artifactStatsSecondContainer { - margin-top: 8px; - font-size: 22px; -} -#artifactStatsSuffix { - display: inline-block; - font-size: 18px; -} -.artifactStatsSuffixBottom { - font-size: 18px; - margin-top: -4px; -} -#artifactStatsThirdMetricContainer { - position: absolute; - margin-top: -120px; - margin-left: 230px; - text-align: center; -} -#artifactStatsMetricSeasonPassLevel { - font-size: 35px; - font-weight: 600; -} -#artifactStatsMetricRankTitle { - font-weight: 600; -} -#artifactStatsMetricFireteamBonus { - margin-top: 10px; -} -#artifactStatsMetricFireteamBonusSuffix { - margin-top: -18px; -} -#artifactStatsArtifactImage { - position: absolute; - margin-top: 5px; - width: 80px; - border: 1px grey dashed; - z-index: -0; -} -#artifactStatsArtifactImage:hover { - filter: blur(3px); - -webkit-filter: blur(3px); -} -#artifactStatsArtifactBonus { - position: absolute; - margin-top: 64px; - margin-left: 3px; - font-size: 20px; - font-weight: 600; - color: #8DDBFF; - z-index: 10; -} -#artifactStatsNoArtifactIsPresent { - position: absolute; - display: none; - margin-top: -80px; - margin-left: 13px; - color: white; - font-size: 15px; - font-style: italic; -} - #burgerStackIcon { display: none; margin-top: 3px; @@ -1594,150 +1472,6 @@ hr.dropdownSubline { background-color: #575757; } - -/* Season pass statistic container */ -#seasonPass { - display: block; - margin-top: 15px; - text-align: center; -} -#seasonPassBg { - background-image: url('../static/images/seasonal_background.jpg'); - background-size: cover; - width: 100%; - height: 100%; - z-index: -1; - filter: brightness(50%) blur(var(--blurFilterAmount)); -} -#seasonPassContentContainer { - position: absolute; - text-align: left; - margin-top: -140px; - margin-left: 15px; -} -#seasonPassFirstContainer { - margin-top: 13px; - font-size: 22px; -} -#seasonPassSecondContainer { - margin-top: 30px; - font-size: 22px; -} -#seasonPassSuffix { - display: inline-block; - font-size: 18px; -} -#seasonPassSuffixBottom { - position: absolute; - font-size: 18px; - margin-top: -3px; -} -#seasonPassThirdMetricContainer { - position: absolute; - margin-top: -130px; - margin-left: 190px; - text-align: center; -} -#seasonPassRankLevel { - margin-left: 50px; - font-size: 35px; - font-weight: 600; -} -#seasonPassRankTitle { - margin-left: 50px; - font-weight: 600; -} -#seasonPassFireteamBonusContainer { - display: inline-block; - margin-right: 5px; -} -#seasonPassFireteamBonus { - margin-top: 10px; - color: #8DDBFF; -} -#seasonPassFireteamBonusSuffix { - margin-top: -18px; - font-weight: 600; -} -#seasonPassXpBonusContainer { - position: absolute; - display: inline-block; - margin-left: 5px; -} -#seasonPassXpBonus { - margin-top: 10px; - color: #8DDBFF; -} -#seasonPassXpBonusSuffix { - margin-top: -18px; - font-weight: 600; -} - - -/* Bright engram statistic container */ -#brightEngram { - display: none; - margin-left: 20px; - text-align: center; -} -#brightEngramBg { - background-image: url('../static/images/eververse.png'); - background-size: cover; - width: 100%; - height: 100%; - z-index: -1; - filter: brightness(50%) blur(var(--blurFilterAmount)); -} -#brightEngramContentContainer { - position: absolute; - text-align: left; - margin-top: -140px; - margin-left: 15px; -} -#brightEngramFirstContainer { - margin-top: 15px; - font-size: 22px; -} -#brightEngramSuffix { - display: inline-block; - font-size: 18px; -} -#brightEngramSecondContainer { - margin-top: 40px; - font-size: 22px; -} -#brightEngramEngramImageLeft { - position: absolute; - margin-top: -140px; - margin-left: 35px; - width: 45px; - z-index: 1; -} -#brightEngramEngramImageMiddle { - position: absolute; - margin-top: -140px; - margin-left: 50px; - width: 100px; - z-index: 2; -} -#brightEngramEngramImageRight { - position: absolute; - margin-top: -140px; - margin-left: 120px; - width: 45px; - z-index: 1; -} -#brightEngramSuffixBottom { - position: absolute; - font-size: 18px; - margin-top: -3px; -} -#brightEngranTooltip { - position:absolute; - font-size: 13px; - font-style: italic; -} - /* Animations */ @keyframes skeletonLoadAnimation { 0% {background-color: rgba(147, 147, 147, 0.3);} diff --git a/src/styles/viewports.css b/src/styles/viewports.css index 6d84377..0fdf867 100644 --- a/src/styles/viewports.css +++ b/src/styles/viewports.css @@ -3,12 +3,6 @@ * * Style for various viewports */ -@media screen and (max-width: 1759px) { - #brightEngram { - margin-left: 0px; - } -} - @media screen and (max-width: 1729px) { #brightEngram { margin-top: 20px; @@ -28,18 +22,6 @@ } } -@media screen and (max-width: 1175px) { - #seasonPass { - margin-left: 0px; - } -} - -@media screen and (max-width: 1144px) { - #seasonPass { - margin-top: 20px; - } -} - @media screen and (max-width: 1100px) { #skeletonCellLeft { display: none; @@ -72,6 +54,10 @@ #recommendationTooltip { margin-bottom: 50px; } + + #bottomUserToggle { + margin-bottom: 70px; + } } @media screen and (max-width: 1050px) { @@ -137,40 +123,16 @@ @media screen and (max-width: 757px) { - .classBg { - width: 75%; - } - - .classType { - margin-left: 65px; - font-size: 25px; - } - .classLight { margin-top: 29px; margin-left: 80px; font-size: 20px; } - .lightIcon { - margin-top: 33px; - margin-left: 67px; - width: 13px; - } - - #categories > div { - margin-top: 5px; - font-size: 18px; - } - #satisticsLayoutContainer { text-align: center; } - #statsTableLayoutContainer { - text-align: center; - } - #brightEngram { margin-bottom: 50px; } @@ -186,6 +148,11 @@ @media screen and (max-width: 645px) { + body { + height: auto; + overflow-y: unset; + } + hr { margin-left: -10px; left: 0; @@ -210,10 +177,6 @@ overflow: unset; } - #mobileCharacterSelect { - margin-bottom: -40px; - } - .dropdownContainer { gap: 15px; } @@ -287,10 +250,6 @@ right: 0; } - #mobileCharacterSelect { - display: grid; - } - #defaultCharacterSelect { display: none; } diff --git a/src/user.html b/src/user.html index ad4d880..adc7003 100644 --- a/src/user.html +++ b/src/user.html @@ -11,8 +11,8 @@ - - + + D2 Synergy @@ -32,7 +32,7 @@
- +
@@ -44,15 +44,15 @@
- +
Bounties
- +
Seasonal
- +
Statistics
@@ -61,15 +61,6 @@
- -
-
-
-
-
-
-
-
@@ -128,14 +119,18 @@

General Options

Refresh data every 2 minutes
-

@@ -229,94 +224,6 @@

Additional Options

- -
- -
-
-
-
- - - - -
- -
-
-
- - - - -
- -
-
-
- - - - -
-
- -
-
Seasonal Challenges
-
Bounties
-
- -
- -
-
Base Yield
-
This is NOT calculated with any XP modifiers.
- -
- -
-
XP: 

-
SP Levels: 
-
- -
-
Net Breakdown
-
- -
-
- - -
Bonus XP
-
-
-
-
- -
- - -
Ghost Mods
-
-
-
-
- -
- - -
Shared Wisdom
-
-
-
-
- -
Net XP: 

-
-
- -
-
@@ -348,7 +255,7 @@

Additional Options

Warlock
- +
9999
@@ -357,30 +264,35 @@

Additional Options

-
- -
-
-
-
- -
----
+ + +
+
+ +
+
+
+
+ +
----
+
+
+ +
+ +
----
+
+
+ +
+ +
----
+
-
- -
- -
----
-
-
- -
- -
----
-
+
@@ -394,23 +306,36 @@

Additional Options

- - - -
-
- -
Synergies
-
🛠️ In (heavy) Development 🚧
-
- -
-
-
Destinations: 
There are no (specific) relations for destinations.
-
- -
-
Activity Modes: 
There are no (specific) relations for activities.
-
- -
-
Weapon Types: 
There are no (specific) relations for weapon types.
-
- -
-
Kill Types: 
There are no (specific) relations for kill types.
-
- -
-
Elemental Types: 
There are no (specific) relations for element types.

-
Ammo Types: 
There are no (specific) relations for ammo types.
-
-
- -
+
+
+
+
+
Season 20
+
Season of Dawn
+
+
+ +
+
+
Season Pass
+
Rank
+
+
+ +
4657
+
+
-
-
-
-
EDZ
-
0%
-
-
-
Nessus
-
0%
-
-
-
TangledShore
-
0%
-
-
-
DreamingCity
-
0%
-
-
-
Moon
-
0%
-
-
-
Europa
-
0%
-
-
-
Cosmodrome
-
0%
-
-
-
Throneworld
-
0%
-
-
+
+
+
Season Rank
+
Next Rank
+
+
+ +
+
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
+
+
+
All-time High
+
Rank
+
+
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
-
+
+
+
Season Pass
+
Rewards
+
+
-
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
- -
-
-
Melee
-
0%
+
+
+
Lantern of Osiris
+
Seasonal Artifact
-
-
Super
-
0%
-
-
-
Grenade
-
0%
-
-
-
Finisher
-
0%
-
-
-
Precision
-
0%
-
-
-
ClassAbility
-
0%
-
-
-
CloseRange
-
0%
-
-
-
RapidKills
-
0%
-
-
-
NoReload
-
0%
-
-
-
GuardianKills
-
0%
-
-
-
InASingleLife
-
0%
-
-
-
- -
-
-
-
-
NightmareHunt
-
0%
-
-
-
Gambit
-
0%
-
-
-
Strike
-
0%
-
-
-
Nightfall
-
0%
-
-
-
Crucible
-
0%
-
-
-
Mayhem
-
0%
-
-
-
Control
-
0%
-
-
-
Breakthrough
-
0%
-
-
-
Countdown
-
0%
-
-
-
Elimination
-
0%
-
-
-
Doubles
-
0%
-
-
-
Supremacy
-
0%
-
-
-
Rumble
-
0%
-
-
-
Survival
-
0%
-
-
-
IronBanner
-
0%
-
-
-
Dungeon
-
0%
-
-
-
Story
-
0%
-
-
-
Trials
-
0%
-
-
-
Explore
-
0%
+
+
+
+
Artifact Power
+
Bonus
+
-
-
DofE
-
0%
+
+
+
Artifact Progress
+
Perks
+
-
-
Raid
-
0%
+
+
+
All-time High
+
Bonus
+
-
-
Clash
-
0%
-
-
-
Momentum
-
0%
-
-
-
Scorched
-
0%
+
+
+
+
+
Eververse Shloot
+
Bright Engram Progression
+
+
+
+
+
Bright Engram
+
Progress
+
-
-
Lockdown
-
0%
+
+
+
Season Progress
+
Total
+
-
-
Showdown
-
0%
+
+
+
All-time High
+
Total
+
-
-
EmpireHunt
-
0%
+
+
+
+
+
General
+
XP Progression
+
+
+
+
+
Season Progress
+
Total XP
+
-
-
Expedition
-
0%
+
+
+
Current Session
+
Progress
+
-
-
KetchCrash
-
0%
+
+
+
All-time High
+
Total XP
+
-
- -
Bounties

-
total  · 
-
completed  · 
-
expired
-
- -
-
-
-
Clear Filters
-
-
-
Toggle Filters
-
-
- -
-
- -
Seasonal Challenges

-
total  · 
-
completed  · 
-
outstanding
-
- -
-
- -
- - - -
- -
-
- -
Synergies
-
🛠️ In (heavy) Development 🚧
-
- -
- -
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
-
- -
-
- -
0%
-
-
- -
0%
-
-
- -
0%
-
+
+ +
Hide Tooltips
-
-
-
- -
Levelling Statistics
-
Season of Plunder
-
- -
- -
-
-
-
ARTIFACT STATS
-
-
 XP

-
to next power bonus
-
-
-
 XP

-
to next artifact unlock
-
-
-
- -
-
-
No Artifact is present on this profile.
-
- - -
-
-
-
SEASON PASS
-
-
 XP

to next rank
-
-
-
 XP

to rank 100
-
-
-
-
-
RANK
-
-

Shared
Wisdom
-
-
-

Bonus XP
-
-
-
- -
-
-
-
BRIGHT ENGRAMS
-
-
 XP

to next engram
-
-
-
 bright engrams earned
-
-
-
Note: Engram statistics may be inaccurate
- - - -
- -
- -